home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / actions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-29  |  76.5 KB  |  2,932 lines  |  [TEXT/KAHL]

  1. /* Implementations of Xconq actions.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* The general theory of actions is that interface or AI code calls, for
  11.    an action foo, the routine prep_foo_action, which just records the action
  12.    for later execution.  The action loop in run_game eventually calls
  13.    do_foo_action, which first calls check_foo_action to confirm that the
  14.    action will succeed.  If check_foo_action does not find any errors, then
  15.    the action cannot fail.  The main body of do_foo_action then implements
  16.    the effects of the action.  Interfaces may call check_foo_action freely,
  17.    but should never call do_foo_action directly. */
  18.  
  19. #include "conq.h"
  20. extern void compute_acp PROTO ((Unit *unit));
  21.  
  22. #define angle_with(d1, d2)  \
  23.   min((d1-d2+NUMDIRS)%NUMDIRS, (d2-d1+NUMDIRS)%NUMDIRS)
  24.  
  25. static void play_action_messages PROTO ((Unit *unit, Action *action));
  26.  
  27. /* Declare the do_xxx_action functions as static, partly to keep them from
  28.    conflicting with do_xxx commands, and partly because they shouldn't be
  29.    visible everywhere. */
  30.  
  31. /* (Alas, xrefs between actions.c and combat.c preclude the static decl,
  32.    but still don't declare the do_... functions in a globally visible place.) */
  33.  
  34. #undef  DEF_ACTION
  35. #define DEF_ACTION(name,code,args,prepfn,DOFN,checkfn,ARGDECL,doc)  \
  36.   extern int DOFN PROTO (ARGDECL);
  37.  
  38. #include "action.def"
  39.  
  40. /* The table of all the types of actions. */
  41.  
  42. ActionDefn actiondefns[] = {
  43.  
  44. #undef  DEF_ACTION
  45. #define DEF_ACTION(NAME,CODE,ARGS,prepfn,DOFN,CHECKFN,argdecl,doc)  \
  46.     { CODE, NAME, ARGS, DOFN, CHECKFN },
  47.  
  48. #include "action.def"
  49.  
  50.     { -1, NULL, NULL, NULL }
  51. };
  52.  
  53. /* This is used to indicate that a move is a retreat; for normal movement it will
  54.    always be false. */
  55.  
  56. int retreating;
  57.  
  58. /* This is a specific type of unit that the retreater is running away from. */
  59.  
  60. int retreating_from = NONUTYPE;
  61.  
  62. char *actiondesigbuf = NULL;
  63.  
  64. /* Do any action-related initialization. */
  65.  
  66. void
  67. init_actions()
  68. {
  69. }
  70.  
  71. /* Just a placeholder action, so not much to do here. */
  72.  
  73. /* static */ int
  74. do_none_action(unit, unit2)
  75. Unit *unit, *unit2;
  76. {
  77.     return A_ANY_DONE;
  78. }
  79.  
  80. /* static */ int
  81. check_none_action(unit, unit2)
  82. Unit *unit, *unit2;
  83. {
  84.     return A_ANY_DONE;
  85. }
  86.  
  87. /* Movement actions. */
  88.  
  89. /* Record a move action as the next to do. */
  90.  
  91. int
  92. prep_move_action(unit, unit2, x, y, z)
  93. Unit *unit, *unit2;
  94. int x, y, z;
  95. {
  96.     if (unit == NULL || unit->act == NULL)
  97.       return FALSE;
  98.     if (unit2 == NULL)
  99.       return FALSE;
  100.     unit->act->nextaction.type = A_MOVE;
  101.     unit->act->nextaction.args[0] = x;
  102.     unit->act->nextaction.args[1] = y;
  103.     unit->act->nextaction.args[2] = z;
  104.     unit->act->nextaction.actee = unit2->id;
  105.     return TRUE;
  106. }
  107.  
  108. /* The basic act of moving.  This attempts to move and maybe fails, but
  109.    takes no corrective action.  Note that this requires space in the
  110.    destination cell, will not board, attack, etc - all that is task- and
  111.    plan-level behavior. */
  112.  
  113. /* static */ int
  114. do_move_action(unit, unit2, nx, ny, nz)
  115. Unit *unit, *unit2;
  116. int nx, ny, nz;
  117. {
  118.     int u, u2, t, rslt, speed, mpcost = 0, acpcost, ox, oy, oz;
  119.  
  120.     u = unit->type;  u2 = unit2->type;
  121.     t = terrain_at(nx, ny);
  122.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  123.     speed = 100;
  124.     mpcost = 1;
  125.     if (!inside_area(nx, ny)) {
  126.     kill_unit(unit2, H_UNIT_LEFT_WORLD);
  127.     rslt = A_ANY_DONE;
  128.     } else if (ut_vanishes_on(u2, t) && !can_move_via_conn(unit2, nx, ny)) {
  129.     kill_unit(unit2, H_UNIT_VANISHED);
  130.     rslt = A_ANY_DONE; /* should return something else :-) */
  131.     } else if (ut_wrecks_on(u2, t) && !can_move_via_conn(unit2, nx, ny)) {
  132.     if (u_wrecked_type(u2) == NONUTYPE) {
  133.         /* Occupants always die if the wrecked unit disappears. */
  134.         kill_unit(unit, H_UNIT_WRECKED);
  135.     } else if (ut_vanishes_on(u_wrecked_type(u2), t)) {
  136.         /* Change the unit's type at its *current* location. */
  137.         change_unit_type(unit2, u_wrecked_type(u2), H_UNIT_WRECKED);
  138.         /* Restore to default hp for the new type. */
  139.         unit2->hp = unit2->hp2 = u_hp(u2);
  140.         /* Get rid of occupants if now overfull. */
  141.         eject_excess_occupants(unit2);
  142.     } else {
  143.         speed = unit_speed(unit2, nx, ny);
  144.         mpcost = move_unit(unit2, nx, ny);
  145.         /* Change the unit's type at its new location. */
  146.         change_unit_type(unit2, u_wrecked_type(u2), H_UNIT_WRECKED);
  147.         /* Restore to default hp for the new type. */
  148.         unit2->hp = unit2->hp2 = u_hp(u2);
  149.         /* Get rid of occupants if now overfull. */
  150.         eject_excess_occupants(unit2);
  151.     }
  152.     rslt = A_ANY_DONE;
  153.     } else {
  154.     speed = unit_speed(unit2, nx, ny);
  155.     mpcost = move_unit(unit2, nx, ny);
  156.     /* ZOC move cost is added after action is done. */
  157.         mpcost += zoc_move_cost(unit2, ox, oy, oz);
  158.     rslt = A_ANY_DONE;
  159.     }
  160.     if (alive(unit)) {
  161.         if (speed > 0) {
  162.         acpcost = (mpcost * 100) / speed;
  163.     } else {
  164.         acpcost = 1;
  165.     }
  166.     acpcost = max(acpcost, u_acp_to_move(u2));
  167.     if (acpcost < 1) acpcost = 1;
  168.     use_up_acp(unit, acpcost);
  169.     }
  170.     /* Count the unit as having actually moved. */
  171.     if (alive(unit2) && unit2->act)
  172.       ++(unit2->act->actualmoves);
  173.     return rslt;
  174. }
  175.  
  176. int
  177. check_move_action(unit, unit2, nx, ny, nz)
  178. Unit *unit, *unit2;
  179. int nx, ny, nz;
  180. {
  181.     int u, u2, u3, ox, oy, oz, acp, acpavail, mpavail, totcost, m, speed;
  182.  
  183.     if (!in_play(unit))
  184.       return A_ANY_ERROR;
  185.     if (!in_play(unit2))
  186.       return A_ANY_ERROR;
  187.     /* Note that edge cell dests (used to leave the world) are allowed. */
  188.     if (!in_area(nx, ny))
  189.       return A_ANY_ERROR;
  190.     u = unit->type;  u2 = unit2->type;
  191.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  192.     acp = u_acp_to_move(u2);
  193.     if (acp < 1)
  194.       return A_ANY_CANNOT_DO;
  195.     acpavail = unit->act->acp;
  196.     /* If this action is a part of retreating, add more acp to represent the
  197.        motivational power of needing to run away... */
  198.     if (retreating && unit == unit2) {
  199.     if (retreating_from != NONUTYPE) {
  200.         acpavail += uu_acp_retreat(u2, retreating_from);
  201.     }
  202.     }
  203.     /* (should not have to modify the unit, but succeeding calls need this) */
  204.     unit->act->acp = acpavail;
  205.     if (!can_have_enough_acp(unit, acp))
  206.       return A_ANY_CANNOT_DO;
  207.     if (!has_enough_acp(unit, acp))
  208.       return A_ANY_NO_ACP;
  209.     if (!has_supply_to_act(unit2))
  210.       return A_ANY_NO_MATERIAL;
  211.     /* Destination is outside the world and we're not allowed to leave. */
  212.     if (!inside_area(nx, ny) && u_mp_to_leave_world(u2) < 0)
  213.     return A_MOVE_CANNOT_LEAVE_WORLD;
  214.     /* Check if the destination is within our move range. */
  215.     /* (also check for and maybe allow border slides here) */
  216.     if (distance(ox, oy, nx, ny) > u_move_range(u2))
  217.       return A_MOVE_TOO_FAR;
  218.     if (nz > 0)
  219.       return A_MOVE_TOO_FAR;
  220.     /* Check if the destination is in a blocking ZOC. */
  221.     if (in_blocking_zoc(unit, nx, ny, nz))
  222.       return A_ANY_ERROR;
  223.     /* Now start looking at the move costs. */
  224.     u3 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  225.     totcost = total_move_cost(u2, u3, ox, oy, oz, nx, ny, nz);
  226.     speed = unit_speed(unit2, nx, ny);
  227.     mpavail = (unit->act->acp * speed) / 100;
  228.     /* Zero mp always disallows movement, unless intra-cell. */
  229.     if (mpavail <= 0 && !(ox == nx && oy == ny && oz == nz))
  230.       return A_MOVE_NO_MP;
  231.     /* The free mp might get us enough moves, so add it before comparing. */
  232.     if (mpavail + u_free_mp(u2) < totcost)
  233.       return A_MOVE_NO_MP;
  234.     /* If destination is too small or already full, we can't move into it. */
  235.     if ((nz & 1) == 0) {
  236.     if (!can_occupy_cell(unit2, nx, ny))
  237.       return A_MOVE_DEST_FULL;
  238.     } else {
  239.     if (!can_occupy_conn(unit2, nx, ny, nz))
  240.       return A_MOVE_DEST_FULL;
  241.     }
  242.     /* We have to have a minimum level of supply to be able to move. */
  243.     for_all_material_types(m) {
  244.     if (unit2->supply[m] < um_to_move(u2, m))
  245.       return A_ANY_NO_MATERIAL;
  246.     }
  247.     return A_ANY_OK;
  248. }
  249.  
  250. int
  251. can_move_via_conn(unit, nx, ny)
  252. Unit *unit;
  253. int nx, ny;
  254. {
  255.     int c, dir;
  256.  
  257.     if (numconntypes == 0)
  258.       return FALSE;
  259.     for_all_terrain_types(c) {
  260.         if (t_is_connection(c)
  261.         && aux_terrain_defined(c)
  262.         && (dir = closest_dir(nx - unit->x, ny - unit->y)) >= 0
  263.         && connection_at(unit->x, unit->y, dir, c)
  264.         && !ut_vanishes_on(unit->type, c)
  265.         && !ut_wrecks_on(unit->type, c)) {
  266.         return TRUE;
  267.         }
  268.     }
  269.     return FALSE;
  270. }
  271.  
  272. /* (should move to unit.c) */
  273.  
  274. int
  275. can_occupy_conn(unit, nx, ny, nz)
  276. Unit *unit;
  277. int nx, ny, nz;
  278. {
  279.     int c, dir, numhere;
  280.     Unit *unit2;
  281.  
  282.     /* (this never happens maybe?) */
  283.     if (numconntypes == 0)
  284.       return FALSE;
  285.     c = nz / 2;
  286.     if (t_is_connection(c)
  287.     && aux_terrain_defined(c)
  288.     && (dir = closest_dir(nx - unit->x, ny - unit->y)) >= 0
  289.     && connection_at(unit->x, unit->y, dir, c)) {
  290.     numhere = 0;
  291.     for_all_stack(nx, ny, unit2) {
  292.         if (unit->z == nz) {
  293.         ++numhere;
  294.         }
  295.     }
  296.     if (numhere + 1 <= ut_capacity_x(unit->type, c))
  297.       return FALSE;
  298.     /* (should also calc general fullness) */
  299.     return FALSE;
  300.     } else {
  301.     run_warning("%s is on an invalid connection type %d?",
  302.             unit_desig(unit), c);
  303.     }
  304.     return TRUE;
  305. }
  306.  
  307. int
  308. unit_speed(unit, nx, ny)
  309. Unit *unit;
  310. int nx, ny;
  311. {
  312.     int u = unit->type, speed, x = unit->x, y = unit->y /*, angle */;
  313.     int occeff, totocceff, totoccdenom;
  314.     Unit *occ;
  315.     
  316.     speed = u_speed(u);
  317.     if (unit->hp < u_hp_max(u) && u_speed_damage_effect(u) != lispnil) {
  318.     speed = damaged_value(unit, u_speed_damage_effect(u), speed);
  319.     }
  320.     if (winds_defined() && u_speed_wind_effect(u) != lispnil) {
  321.     speed *= wind_force_at(x, y);
  322.     }
  323. #if 0
  324.     if (winds_defined() && u_speed_wind_angle_effect(u) != lispnil) {
  325.     angle = angle_with(closest_dir(nx - x, nx - y), wind_dir_at(x, y));
  326.     speed += angle * wind_force_at(x, y);
  327.     }
  328. #endif
  329.     if (unit->occupant /* and any occupant speed effects */) {
  330.         totocceff = 100;
  331.         totoccdenom = 100;
  332.         for_all_occupants(unit, occ) {
  333.         if (completed(occ)) {
  334.         occeff = uu_speed_occ_effect(u, occ->type);
  335.         if (occeff != 100) {
  336.             totocceff *= occeff;
  337.             totoccdenom *= 100;
  338.         }
  339.         }
  340.         }
  341.         speed = (speed * totocceff) / totoccdenom;
  342.     }
  343.     /* Clip to limits. */
  344.     speed = max(speed, u_speed_min(u));
  345.     speed = min(speed, u_speed_max(u));
  346.     return speed;
  347. }
  348.  
  349. /* Compute and return the acp of a damaged unit, using a list of (hp acp) pairs
  350.    and interpolating between them. */
  351.  
  352. int
  353. damaged_value(unit, effect, maxval)
  354. Unit *unit;
  355. Obj *effect;
  356. int maxval;
  357. {
  358.     int hp = unit->hp, thishp, thisval, nexthp, nextval, rslt;
  359.     Obj *rest;
  360.  
  361.     for (rest = effect; rest != lispnil; rest = cdr(rest)) {
  362.     thishp = c_number(car(car(rest)));
  363.     thisval = c_number(cadr(car(rest)));
  364.     if (cdr(rest)) {
  365.         nexthp = c_number(car(cadr(rest)));
  366.         nextval = c_number(cadr(cadr(rest)));
  367.     } else {
  368.         nexthp = u_hp_max(unit->type);
  369.         nextval = maxval;
  370.     }
  371.     if (unit->hp < thishp) {
  372.         /* Interpolate between thishp and 0. */
  373.         return (thisval * hp) / thishp;
  374.     } else if (between(thishp, unit->hp, nexthp)) {
  375.         rslt = thisval;
  376.         if (unit->hp != thishp) {
  377.         /* Add the linear interpolation. */
  378.             rslt += ((nextval - thisval) * (hp - thishp)) / (nexthp - thishp);
  379.         }
  380.         return rslt;
  381.     }
  382.     }
  383.     return maxval;
  384. }
  385.  
  386. /* Conduct the actual move (used in both normal moves and some combat).
  387.    Note that the new x,y may be the same as the old; this will happen
  388.    if an occupant is getting off a transport but staying in the same cell. */
  389.  
  390. int
  391. move_unit(unit, nx, ny)
  392. Unit *unit;
  393. int nx, ny;
  394. {
  395.     int u = unit->type, u3, ox = unit->x, oy = unit->y, oz = unit->z;
  396.     int nz = oz;
  397.     extern int max_detonate_on_approach_range;
  398.  
  399.     u3 = (unit->transport ? unit->transport->type : NONUTYPE);
  400.     /* Disappear from the old location ... */
  401.     leave_cell(unit);
  402.     /* ... and appear in the new one! */
  403.     enter_cell(unit, nx, ny);
  404.     /* Movement may set off other people's alarms. */
  405.     maybe_react_to_move(unit, ox, oy);
  406.     /* Might have auto-detonations in response. */
  407.     if (max_detonate_on_approach_range >= 0) {
  408.     detonate_on_approach_around(unit);
  409.     /* A detonation might have been fatal, get out now if so. */
  410.     if (!alive(unit))
  411.       return 1;
  412.     }
  413.     /* The people at the new location may change sides immediately. */
  414.     if (people_sides_defined()
  415.     && any_people_side_changes
  416.     && probability(people_surrender_chance(u, nx, ny))) {
  417.     change_people_side_around(nx, ny, u, unit->side);
  418.     }
  419.     /* Use up supplies as directed. */
  420.     consume_move_supplies(unit);
  421.     /* a hack */
  422.     update_cell_display(unit->side, ox, oy, TRUE);
  423.     /* Always return the mp cost, even if the mover died. */
  424.     return total_move_cost(u, u3, ox, oy, oz, nx, ny, nz);
  425. }
  426.  
  427. int
  428. can_move_at_all(unit)
  429. Unit *unit;
  430. {
  431.     return u_speed(unit->type) > 0;
  432. }
  433.  
  434. /* This is true if the given location is in a blocking zoc for the unit. */
  435.  
  436. int
  437. in_blocking_zoc(unit, x, y, z)
  438. Unit *unit;
  439. int x, y, z;
  440. {
  441.     int u = unit->type, t = terrain_at(x, y), dir, x1, y1, u2, range;
  442.     Unit *unit2;
  443.  
  444.     if (max_zoc_range < 0)
  445.       return FALSE;
  446.     if (max_zoc_range >= 0) {
  447.     for_all_stack(x, y, unit2) {
  448.         if (unit_blockable_by(unit, unit2)
  449.         && ut_zoc_into(unit2->type, t)
  450.         && ut_zoc_from_terrain(unit2->type, t) > 0)
  451.           return TRUE;
  452.     }
  453.     }
  454.     if (max_zoc_range >= 1) {
  455.     for_all_directions(dir) {
  456.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  457.         for_all_stack(x, y, unit2) {
  458.             u2 = unit2->type;
  459.             range = zoc_range(unit2, u);
  460.             if (unit_blockable_by(unit, unit2)
  461.             && range > 1
  462.             && ut_zoc_into(u2, t))
  463.               return TRUE;
  464.         }
  465.         }
  466.     }
  467.     }
  468.     if (max_zoc_range >= 2) {
  469.     run_warning("Max zoc range >= 2 not implemented");
  470.     }
  471.     return FALSE;
  472. }
  473.  
  474. /* This is true if unit2 wants to block unit from moving. */
  475.  
  476. int
  477. unit_blockable_by(unit, unit2)
  478. Unit *unit, *unit2;
  479. {
  480.     return (unit->side != unit2->side /* should make a better test */
  481.         && uu_mp_to_enter_zoc(unit->type, unit2->type) < 0);
  482. }
  483.  
  484. /* Compute the number of move points that will be needed to do the given
  485.    move. */
  486.  
  487. int
  488. total_move_cost(u, u2, x1, y1, z1, x2, y2, z2)
  489. int u, u2, x1, y1, z1, x2, y2, z2;
  490. {
  491.     int cost, ferry, b, c, conncost, dist, dir;
  492.  
  493.     if (z1 != 0 || z2 != 0) {
  494.         /* should write these calcs eventually */
  495.     }
  496.     dist = distance(x1, y1, x2, y2);
  497.     if (dist == 0) {
  498.     if (z2 != z1) {
  499.         /* (should have parms for up/down in same cell) */
  500.         return 1;
  501.     } else {
  502.             /* Unit is leaving a transport and moving into the open here;
  503.                free of charge. */
  504.             return 0;
  505.         }
  506.     } else if (dist == 1) {
  507.         /* (fall through) */
  508.     } else {
  509.         /* Border slide or multiple cell move. */
  510.         /* (should implement) */
  511.         return 9999;
  512.     }
  513.     cost = 0;
  514.     ferry = 0;
  515.     if (u2 != NONUTYPE) {
  516.     /* Charge for leaving the transport. */
  517.         cost += uu_mp_to_leave(u, u2);
  518.         /* See what type of ferrying we're going to get. */
  519.         ferry = uu_ferry_on_leave(u2, u);
  520.     }
  521.     if (ferry < 1) {
  522.         cost += ut_mp_to_leave(u, terrain_at(x1, y1));
  523.     }
  524.     if (numbordtypes > 0 && ferry < 2) {
  525.     /* Add any necessary border crossing costs. */
  526.     dir = closest_dir(x2 - x1, y2 - y1);
  527.     if (dir >= 0) {
  528.         for_all_terrain_types(b) {
  529.         if (t_is_border(b)
  530.             && aux_terrain_defined(b)
  531.             && border_at(x1, y1, dir, b)) {
  532.             cost += ut_mp_to_enter(u, b);
  533.         }
  534.         }
  535.     }
  536.     }
  537.     if (ferry < 3) {
  538.     cost += ut_mp_to_enter(u, terrain_at(x2, y2));
  539.     }
  540.     /* Use a connection traversal if it would be cheaper.  This is
  541.        only automatic if the connection on/off costs are small enough,
  542.        otherwise the unit has to do explicit actions to get on the
  543.        connection and off again. */
  544.     if (numconntypes > 0) {
  545.     /* Try each connection type to see if it's better. */
  546.     dir = closest_dir(x2 - x1, y2 - y1);
  547.     if (dir >= 0) {
  548.         for_all_terrain_types(c) {
  549.         if (t_is_connection(c)
  550.             && aux_terrain_defined(c)
  551.             && connection_at(x1, y1, dir, c)) {
  552.             conncost = ut_mp_to_enter(u, c)
  553.               + ut_mp_to_traverse(u, c)
  554.             + ut_mp_to_leave(u, c);
  555.             cost = min(cost, conncost);
  556.         }
  557.         }
  558.     }
  559.     }
  560.     /* The cost of leaving the world is always an addon. */
  561.     if (!inside_area(x2, y2)) {
  562.         cost += u_mp_to_leave_world(u);
  563.     }
  564.     /* Any (inter-cell) movement must always cost at least 1 mp. */
  565.     if (cost < 1)
  566.       cost = 1;
  567.     return cost;
  568. }
  569.  
  570. int
  571. zoc_range(unit, u2)
  572. Unit *unit;
  573. int u2;
  574. {
  575.     int u = unit->type;
  576.  
  577.     return (uu_zoc_range(u, u2)
  578.         * ut_zoc_from_terrain(u, terrain_at(unit->x, unit->y))) / 100;
  579. }
  580.  
  581. int
  582. zoc_move_cost(unit, ox, oy, oz)
  583. Unit *unit;
  584. int ox, oy, oz;
  585. {
  586.     int u = unit->type, u2, t1, t2, cost, mpcost, dir, x1, y1, range;
  587.     Unit *unit2;
  588.  
  589.     /* If this is negative, ZOCs are not part of this game. */
  590.     if (max_zoc_range < 0)
  591.       return 0;
  592.     if (!in_play(unit))
  593.       return 0;
  594.     mpcost = 0;
  595.     t1 = terrain_at(ox, oy);
  596.     t2 = terrain_at(unit->x, unit->y);
  597.     if (max_zoc_range == 0 || max_zoc_range == 1) {
  598.         /* ZOCs of units in old cell. */
  599.     for_all_stack(ox, oy, unit2) {
  600.         u2 = unit2->type;
  601.             range = zoc_range(unit2, u);
  602.         if (in_play(unit2) /* should be is_active? */
  603.         && unit2->side != unit->side
  604.         && range >= 0
  605.         && ut_zoc_into(u2, t1)
  606.         /* should account for from-terrain also */
  607.         )
  608.           mpcost = max(mpcost, uu_mp_to_leave_zoc(u, u2));
  609.     }
  610.     /* ZOCs of units in new cell. */
  611.     for_all_stack(unit->x, unit->y, unit2) {
  612.         u2 = unit2->type;
  613.             range = zoc_range(unit2, u);
  614.         if (in_play(unit2) /* should be is_active? */
  615.         && unit2->side != unit->side
  616.         && range >= 0
  617.         && ut_zoc_into(u2, t2))
  618.           mpcost = max(mpcost, uu_mp_to_enter_zoc(u, u2));
  619.     }
  620.     }
  621.     if (max_zoc_range > 0) {
  622.       if (max_zoc_range == 1) {
  623.         /* ZOCs may be into adjacent cells. */
  624.         /* Look for everybody that was exerting ZOC into the old location. */
  625.         /* (should calc with stacked units also) */
  626.     for_all_directions(dir) {
  627.         if (point_in_dir(ox, oy, dir, &x1, &y1)) {
  628.         for_all_stack(x1, y1, unit2) {
  629.             u2 = unit2->type;
  630.                     range = zoc_range(unit2, u);
  631.             if (in_play(unit2) /* should be is_active? */
  632.             && unit2->side != unit->side  /* and unfriendly */
  633.             && range >= 1
  634.             && ut_zoc_into(u2, t1)) {
  635.             if (1 /* leaving zoc */) {
  636.                 cost = uu_mp_to_leave_zoc(u, u2);
  637.             } else {
  638.                 cost = uu_mp_to_traverse_zoc(u, u2);
  639.             }
  640.             mpcost = max(mpcost, cost);
  641.             }
  642.             /* (and occupants?) */
  643.         }
  644.         }
  645.     }
  646.         /* Look for everybody that is now exerting ZOC into the new location. */
  647.         /* (should calc with stacked units also) */
  648.     for_all_directions(dir) {
  649.         if (point_in_dir(unit->x, unit->y, dir, &x1, &y1)) {
  650.         for_all_stack(x1, y1, unit2) {
  651.             u2 = unit2->type;
  652.                     range = zoc_range(unit2, u);
  653.             if (in_play(unit2) /* should be is_active? */
  654.             && unit2->side != unit->side  /* and unfriendly */
  655.             && range >= 1
  656.             && ut_zoc_into(u2, t2)) {
  657.             if (1 /* entering zoc */) {
  658.                 cost = uu_mp_to_enter_zoc(u, u2);
  659.             } else {
  660.                 cost = uu_mp_to_traverse_zoc(u, u2);
  661.             }
  662.             mpcost = max(mpcost, cost);
  663.             }
  664.             /* (and occupants?) */
  665.         }
  666.         }
  667.     }
  668.       } else {
  669.     /* General case. */
  670.         /* (should write this case - bleah, complicated) */
  671.         run_error("No zoc ranges > 1 allowed");
  672.       }
  673.     }
  674.     return mpcost;
  675. }
  676.  
  677. /* This is a hook to handle any reactions to the unit's successful move. */
  678.  
  679. int
  680. maybe_react_to_move(unit, ox, oy)
  681. Unit *unit;
  682. int ox, oy;
  683. {
  684.     return 0;
  685. }
  686.  
  687. static void try_detonate_on_approach PROTO ((int x, int y));
  688.  
  689. static void
  690. try_detonate_on_approach(x, y)
  691. int x, y;
  692. {
  693.     int dist;
  694.     Unit *unit;
  695.  
  696.     dist = distance(tmpunit->x, tmpunit->y, x, y);
  697.     for_all_stack(x, y, unit) {
  698.     if (unit->side != tmpunit->side
  699.         && uu_detonate_approach_range(unit->type, tmpunit->type) >= dist
  700.         /* (should make doctrine-based decision about whether to go off) */
  701.         ) {
  702.         detonate_unit(unit, unit->x, unit->y, unit->z);
  703.     }
  704.     }
  705. }
  706.  
  707. void
  708. detonate_on_approach_around(unit)
  709. Unit *unit;
  710. {
  711.     int maxrange;
  712.     extern int maxudetonaterange, maxtdetonaterange;
  713.     extern int max_detonate_on_approach_range;
  714.  
  715.     tmpunit = unit;
  716.     apply_to_area(unit->x, unit->y, max_detonate_on_approach_range, try_detonate_on_approach);
  717.     maxrange = max(maxudetonaterange, maxtdetonaterange) + max_detonate_on_approach_range;
  718.     reckon_damage_around(unit->x, unit->y, maxrange);
  719. }
  720.  
  721. /* Use up the supply consumed by a successful move.  Also, the move might
  722.    have used up essentials and left the unit without its survival needs,
  723.    so check for this case and maybe hit/kill the unit. */
  724.  
  725. void  
  726. consume_move_supplies(unit)
  727. Unit *unit;
  728. {
  729.     int u = unit->type, m, checkstarve = FALSE;
  730.     
  731.     for_all_material_types(m) {
  732.     if (um_consumption_per_move(u, m) > 0) {
  733.         unit->supply[m] -= um_consumption_per_move(u, m);
  734.         /* Don't let supply go below zero. */
  735.         if (unit->supply[m] <= 0) {
  736.         unit->supply[m] = 0;
  737.         checkstarve = TRUE;
  738.         }
  739.     }
  740.     }
  741.     if (checkstarve)
  742.       maybe_starve(unit, FALSE);
  743.     /* Trigger any supply alarms. */
  744.     if (alive(unit)
  745.         && unit->plan
  746.         && !unit->plan->supply_is_low
  747.         && past_halfway_point(unit)
  748.         ) {
  749.         unit->plan->supply_is_low = TRUE;
  750.         update_unit_display(unit->side, unit, TRUE); 
  751.     }
  752. }
  753.  
  754. /* Movement into another unit. */
  755.  
  756. /* Record an enter action as the next to do. */
  757.  
  758. int
  759. prep_enter_action(unit, unit2, unit3)
  760. Unit *unit, *unit2, *unit3;
  761. {
  762.     if (unit == NULL || unit->act == NULL)
  763.       return FALSE;
  764.     if (unit2 == NULL)
  765.       return FALSE;
  766.     if (unit3 == NULL)
  767.       return FALSE;
  768.     unit->act->nextaction.type = A_ENTER;
  769.     unit->act->nextaction.args[0] = unit3->id;
  770.     unit->act->nextaction.actee = unit2->id;
  771.     return TRUE;
  772. }
  773.  
  774. /* static */ int
  775. do_enter_action(unit, unit2, unit3)
  776. Unit *unit, *unit2, *unit3;
  777. {
  778.     int u2, u3, u4, ox, oy, oz, nx, ny, nz, speed, acpcost, mpcost;
  779.  
  780.     u2 = unit2->type;
  781.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  782.     u3 = unit3->type;
  783.     nx = unit3->x;  ny = unit3->y;  nz = unit3->z;
  784.     /* Change the unit's position. */
  785.     leave_cell(unit2);
  786.     enter_transport(unit2, unit3);
  787.     /* Calculate how much acp has been used up. */
  788.     u4 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  789.     mpcost = total_entry_cost(u2, u4, ox, oy, oz, u3, nx, ny, nz);
  790.     if (alive(unit)) {
  791.     speed = u_speed(u2);
  792.     if (speed > 0) {
  793.         acpcost = (mpcost * 100) / speed;
  794.     } else {
  795.         acpcost = 1;
  796.     }
  797.     use_up_acp(unit, acpcost + uu_acp_to_enter(u2, u3));
  798.     }
  799.     return A_ANY_DONE;
  800. }
  801.  
  802. int
  803. check_enter_action(unit, unit2, unit3)
  804. Unit *unit, *unit2, *unit3;
  805. {
  806.     int u, u2, u3, u4, u2x, u2y, u3x, u3y, totcost, speed, mpavail;
  807.     int ox, oy, oz, nx, ny, nz;
  808.  
  809.     if (!in_play(unit))
  810.       return A_ANY_ERROR;
  811.     if (!in_play(unit2))
  812.       return A_ANY_ERROR;
  813.     if (!in_play(unit3))
  814.       return A_ANY_ERROR;
  815.     u = unit->type;
  816.     u2 = unit2->type;
  817.     u3 = unit3->type;
  818.     if (uu_acp_to_enter(u2, u3) < 1)
  819.       return A_ANY_CANNOT_DO;
  820.     if (!can_have_enough_acp(unit, uu_acp_to_enter(u2, u3)))
  821.       return A_ANY_CANNOT_DO;
  822.     /* Can't enter self. */
  823.     if (unit2 == unit3)
  824.       return A_ANY_ERROR;
  825.     u2x = unit2->x;  u2y = unit2->y;
  826.     u3x = unit3->x;  u3y = unit3->y;
  827.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  828.     nx = unit3->x;  ny = unit3->y;  nz = unit3->z;
  829.     if (!between(0, distance(ox, oy, nx, ny), 1))
  830.       return A_ANY_ERROR;
  831.     if (!sides_allow_entry(unit2, unit3))
  832.       return A_ANY_ERROR;
  833.     if (!can_occupy(unit2, unit3))
  834.       return A_ANY_ERROR;
  835.     if (!has_enough_acp(unit, uu_acp_to_enter(u2, u3)))
  836.       return A_ANY_NO_ACP;
  837.     u4 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  838.     totcost = total_entry_cost(u2, u4, ox, oy, oz, u3, nx, ny, nz);
  839.     speed = u_speed(u2);
  840.     /* (should generalize!) */
  841.     if (winds_defined() && u_speed_wind_effect(u2) != lispnil) {
  842.     speed *= wind_force_at(u3x, u3y);
  843.     }
  844.     if (speed > 0 && unit->act) {
  845.     mpavail = (unit->act->acp * speed) / 100;
  846.     } else {
  847.     mpavail = 0;
  848.     }
  849.     /* If transport picks up the unit itself, no need to check mp. */
  850.     if (uu_ferry_on_enter(u3, u2) < 3) {
  851.     /* Zero mp always disallows movement. */
  852.     if (mpavail <= 0)
  853.       return A_MOVE_NO_MP;
  854.     /* The free mp might get us enough moves, so add it before comparing. */
  855.     if (mpavail + u_free_mp(u2) < totcost)
  856.       return A_MOVE_NO_MP;
  857.     }
  858.     /* (should check materials available) */
  859.     return A_ANY_OK;
  860. }
  861.  
  862. /* This tests whether the relationship between the sides of a unit
  863.    and a prospective transport allows for entry of the unit. */
  864.  
  865. int
  866. sides_allow_entry(unit, transport)
  867. Unit *unit, *transport;
  868. {
  869.     if (unit->side == NULL) {
  870.         if (transport->side == NULL) {
  871.             return TRUE;
  872.         } else {
  873.             return uu_can_enter_indep(unit->type, transport->type);
  874.         }
  875.     } else {
  876.         if (transport->side == NULL) {
  877.             return uu_can_enter_indep(unit->type, transport->type);
  878.         } else {
  879.         /* Note that because this is for an explicit action, the unit
  880.            must trust the transport, so the only test is whether the
  881.            transports trusts the unit enough to have it as an occupant. */
  882.             return unit_trusts_unit(transport, unit);
  883.         }
  884.     }
  885. }
  886.  
  887. /* This computes the total mp cost of entering a transport. */
  888.  
  889. int
  890. total_entry_cost(u1, u3, x1, y1, z1, u2, x2, y2, z2)
  891. int u1, u3, x1, y1, z1, u2, x2, y2, z2;
  892. {
  893.     int cost = 0, ferryout, ferryin, t1, t2, b, dir, conncost, c;
  894.  
  895.     ferryout = 0;
  896.     ferryin = uu_ferry_on_enter(u2, u1);
  897.     if (u3 != NONUTYPE) {
  898.     /* Charge for leaving the transport. */
  899.         cost += uu_mp_to_leave(u1, u3);
  900.         ferryout = uu_ferry_on_leave(u3, u1);
  901.     }
  902.     /* (should include possibility of using conn to cross terrain) */
  903.     /* Maybe add cost to leave terrain of own cell. */
  904.     if (ferryout < 1 && ferryin < 3) {
  905.     t1 = terrain_at(x1, y1);
  906.         cost += ut_mp_to_leave(u1, t1);
  907.     }
  908.     /* Maybe add cost to cross one (or more) borders. */
  909.     if (numbordtypes > 0 && ferryout < 2 && ferryin < 2) {
  910.     dir = closest_dir(x2 - x1, y2 - y1);
  911.     if (dir >= 0) {
  912.         for_all_terrain_types(b) {
  913.         if (t_is_border(b)
  914.             && aux_terrain_defined(b)
  915.             && border_at(x1, y1, dir, b)) {
  916.             cost += ut_mp_to_enter(u1, b);
  917.         }
  918.         }
  919.     }
  920.     }
  921.     /* Maybe even have to pay cost of crossing destination's terrain. */
  922.     if (ferryout < 3 && ferryin < 1) {
  923.     t2 = terrain_at(x2, y2);
  924.         cost += ut_mp_to_enter(u1, t2);
  925.     }
  926.     /* Use a connection traversal if it would be cheaper.  This is
  927.        only automatic if the connection on/off costs are small enough,
  928.        otherwise the unit has to do explicit actions to get on the
  929.        connection and off again. */
  930.     if (numconntypes > 0) {
  931.     /* Try each connection type to see if it's better. */
  932.     dir = closest_dir(x2 - x1, y2 - y1);
  933.     if (dir >= 0) {
  934.         for_all_terrain_types(c) {
  935.         if (t_is_connection(c)
  936.             && aux_terrain_defined(c)
  937.             && connection_at(x1, y1, dir, c)) {
  938.             conncost = ut_mp_to_enter(u1, c)
  939.               + ut_mp_to_traverse(u1, c)
  940.             + ut_mp_to_leave(u1, c);
  941.             cost = min(cost, conncost);
  942.         }
  943.         }
  944.     }
  945.     }
  946.     /* Add the actual cost of entry. */
  947.     cost += uu_mp_to_enter(u1, u2);
  948.     /* Movement must always cost at least 1 mp. */
  949.     if (cost < 1)
  950.       cost = 1;
  951.     return cost;
  952. }
  953.  
  954. /* Material actions. */
  955.  
  956. /* Explicit material production. */
  957.  
  958. int
  959. prep_produce_action(unit, unit2, m, n)
  960. Unit *unit, *unit2;
  961. int m, n;
  962. {
  963.     if (unit == NULL || unit->act == NULL)
  964.       return FALSE;
  965.     if (unit2 == NULL)
  966.       return FALSE;
  967.     unit->act->nextaction.type = A_PRODUCE;
  968.     unit->act->nextaction.args[0] = m;
  969.     unit->act->nextaction.args[1] = n;
  970.     unit->act->nextaction.actee = unit2->id;
  971.     return TRUE;
  972. }
  973.  
  974. /* static */ int
  975. do_produce_action(unit, unit2, m, n)
  976. Unit *unit, *unit2;
  977. int m, n;
  978. {
  979.     int amt;
  980.  
  981.     amt = min(n, um_material_per_production(unit2->type, m));
  982.     unit2->supply[m] += n;
  983.     use_up_acp(unit, um_acp_to_produce(unit2->type, m));
  984.     return A_ANY_DONE;
  985. }
  986.  
  987. int
  988. check_produce_action(unit, unit2, m, n)
  989. Unit *unit, *unit2;
  990. int m, n;
  991. {
  992.     int acp, m2;
  993.  
  994.     if (!in_play(unit))
  995.       return A_ANY_ERROR;
  996.     if (!in_play(unit2))
  997.       return A_ANY_ERROR;
  998.     if (!is_material_type(m))
  999.       return A_ANY_ERROR;
  1000.     acp = um_acp_to_produce(unit2->type, m);
  1001.     if (acp < 1)
  1002.       return A_ANY_CANNOT_DO;
  1003.     if (!can_have_enough_acp(unit, acp))
  1004.       return A_ANY_CANNOT_DO;
  1005.     if (um_material_per_production(unit2->type, m) < 1)
  1006.       return A_ANY_CANNOT_DO;
  1007.     if (!has_enough_acp(unit, acp))
  1008.       return A_ANY_NO_ACP;
  1009.     /* Check that the unit has any required supplies. */
  1010.     for_all_material_types(m2) {
  1011.     if (unit2->supply[m2] < um_to_produce(unit2->type, m2))
  1012.       return A_ANY_NO_MATERIAL;
  1013.     }
  1014.     return A_ANY_OK;
  1015. }
  1016.  
  1017. /* Transfer action. */
  1018.  
  1019. /* This action transfers material from one unit to another. */
  1020.  
  1021. int
  1022. prep_transfer_action(unit, unit2, m, n, unit3)
  1023. Unit *unit, *unit2, *unit3;
  1024. int m, n;
  1025. {
  1026.     if (unit == NULL || unit->act == NULL)
  1027.       return FALSE;
  1028.     if (unit2 == NULL)
  1029.       return FALSE;
  1030.     if (unit3 == NULL)
  1031.       return FALSE;
  1032.     unit->act->nextaction.type = A_TRANSFER;
  1033.     unit->act->nextaction.args[0] = m;
  1034.     unit->act->nextaction.args[1] = n;
  1035.     unit->act->nextaction.args[2] = unit3->id;
  1036.     unit->act->nextaction.actee = unit2->id;
  1037.     return TRUE;
  1038. }
  1039.  
  1040. /* static */ int
  1041. do_transfer_action(unit, unit2, m, n, unit3)
  1042. Unit *unit, *unit2, *unit3;
  1043. int m, n;
  1044. {
  1045.     int actual;
  1046.  
  1047.     if (n > 0) {
  1048.         actual = transfer_supply(unit2, unit3, m, n);
  1049.     } else {
  1050.         actual = transfer_supply(unit3, unit2, m, -n);
  1051.     }
  1052.     use_up_acp(unit, 1);
  1053.     if (actual == n) {
  1054.     return A_ANY_DONE;
  1055.     } else if (actual == 0) {
  1056.     return A_ANY_ERROR;
  1057.     } else {
  1058.         /* (should be able to say that action did not do all that was requested) */
  1059.     return A_ANY_DONE;
  1060.     }
  1061. }
  1062.  
  1063. int
  1064. check_transfer_action(unit, unit2, m, n, unit3)
  1065. Unit *unit, *unit2, *unit3;
  1066. int m, n;
  1067. {
  1068.     if (!in_play(unit))
  1069.       return A_ANY_ERROR;
  1070.     if (!in_play(unit2))
  1071.       return A_ANY_ERROR;
  1072.     if (!is_material_type(m))
  1073.       return A_ANY_ERROR;
  1074.     if (n == 0)
  1075.       return A_ANY_ERROR;
  1076.     if (!in_play(unit3))
  1077.       return A_ANY_ERROR;
  1078.     if (um_acp_to_unload(unit2->type, m) < 1)
  1079.       return A_ANY_CANNOT_DO;
  1080.     if (unit3->act && um_acp_to_load(unit3->type, m) < 1)
  1081.       return A_ANY_CANNOT_DO;
  1082.     if (!can_have_enough_acp(unit, 1))
  1083.       return A_ANY_CANNOT_DO;
  1084.     if (n > 0) {
  1085.     if (unit2->supply[m] <= 0)
  1086.       return A_ANY_ERROR;
  1087.     if (um_storage_x(unit3->type, m) == 0)
  1088.       return A_ANY_ERROR;
  1089.     } else {
  1090.     if (unit3->supply[m] <= 0)
  1091.       return A_ANY_ERROR;
  1092.     if (um_storage_x(unit2->type, m) == 0)
  1093.       return A_ANY_ERROR;
  1094.     }
  1095.     if (!has_enough_acp(unit, 1))
  1096.       return A_ANY_NO_ACP;
  1097.     return A_ANY_OK;
  1098. }
  1099.  
  1100. /* Move supply from one unit to another.  Don't move more than is possible;
  1101.    check both from and to amounts and capacities. */
  1102.  
  1103. int
  1104. transfer_supply(from, to, m, amount)
  1105. Unit *from, *to;
  1106. int m, amount;
  1107. {
  1108.     int origfrom = from->supply[m], origto = to->supply[m];
  1109.  
  1110.     amount = min(amount, origfrom);
  1111.     amount = min(amount, um_storage_x(to->type, m) - origto);
  1112.     if (um_unload_max(from->type, m) >= 0) {
  1113.     amount = min(amount, um_unload_max(from->type, m));
  1114.     }
  1115.     if (um_load_max(to->type, m) >= 0) {
  1116.     amount = min(amount, um_load_max(to->type, m));
  1117.     }
  1118.     from->supply[m] -= amount;
  1119.     to->supply[m] += amount;
  1120.     /* Make sure any displays of supply levels see the transfer. */
  1121.     update_unit_display(from->side, from, TRUE); 
  1122.     update_unit_display(to->side, to, TRUE); 
  1123.     Dprintf("%s (had %d) transfers %d %s to %s (had %d)\n",
  1124.         unit_desig(from), origfrom, amount, m_type_name(m),
  1125.         unit_desig(to), origto);
  1126.     return amount;
  1127. }
  1128.  
  1129. /* Research action. */
  1130.  
  1131. /* If a side's tech level is under its max, research can increase it. */
  1132.  
  1133. int
  1134. prep_research_action(unit, unit2, u3)
  1135. Unit *unit, *unit2;
  1136. int u3;
  1137. {
  1138.     if (unit == NULL || unit->act == NULL)
  1139.       return FALSE;
  1140.     if (unit2 == NULL)
  1141.       return FALSE;
  1142.     unit->act->nextaction.type = A_RESEARCH;
  1143.     unit->act->nextaction.args[0] = u3;
  1144.     unit->act->nextaction.actee = unit2->id;
  1145.     return TRUE;
  1146. }
  1147.  
  1148. /* static */ int
  1149. do_research_action(unit, unit2, u3)
  1150. Unit *unit, *unit2;
  1151. int u3;
  1152. {
  1153.     int u2 = unit2->type, lim;
  1154.     Side *side = unit2->side;
  1155.  
  1156.     side->tech[u3] += prob_fraction(uu_tech_per_research(u2, u3));
  1157.     /* Silently apply the per-side-per-turn limit on tech gains. */
  1158.     lim =  side->inittech[u3] + u_tech_per_turn_max(u3);
  1159.     if (side->tech[u3] > lim)
  1160.       side->tech[u3] = lim;
  1161.     /* Adjust the tech levels of any related unit types to match. */
  1162.     adjust_tech_crossover(side, u3);
  1163.     /* (should notify side about changes and/or thresholds reached?) */
  1164.     use_up_acp(unit, uu_acp_to_research(u2, u3));
  1165.     return A_ANY_DONE;
  1166. }
  1167.  
  1168. int
  1169. check_research_action(unit, unit2, u3)
  1170. Unit *unit, *unit2;
  1171. int u3;
  1172. {
  1173.     int u, u2;
  1174.     Side *side;
  1175.  
  1176.     if (!in_play(unit))
  1177.       return A_ANY_ERROR;
  1178.     if (!in_play(unit2))
  1179.       return A_ANY_ERROR;
  1180.     if (!is_unit_type(u3))
  1181.       return A_ANY_ERROR;
  1182.     u = unit->type;
  1183.     u2 = unit2->type;
  1184.     side = unit->side;
  1185.     /* Independent units don't do research. */
  1186.     if (side == NULL)
  1187.       return A_ANY_ERROR;
  1188.     /* This unit must be of a type that can research the given type. */
  1189.     if (uu_acp_to_research(u2, u3) < 1)
  1190.       return A_ANY_CANNOT_DO;
  1191.     if (!can_have_enough_acp(unit, uu_acp_to_research(u2, u3)))
  1192.       return A_ANY_CANNOT_DO;
  1193.     /* Max tech level means there's nothing more to learn. */
  1194.     if (side->tech[u3] >= u_tech_max(u3))
  1195.       return A_ANY_ERROR;
  1196.     if (!has_enough_acp(unit, uu_acp_to_research(u2, u3)))
  1197.       return A_ANY_NO_ACP;
  1198.     return A_ANY_OK;
  1199. }
  1200.  
  1201. /* For all unit types, bring their tech level up to match the crossovers
  1202.    from the given unit type. */
  1203.  
  1204. void
  1205. adjust_tech_crossover(side, u)
  1206. Side *side;
  1207. int u;
  1208. {
  1209.     int u2, cross;
  1210.  
  1211.     for_all_unit_types(u2) {
  1212.     if (u2 != u) {
  1213.         /* (should be "as ratio of max levels for each type") */
  1214.         cross = (uu_tech_crossover(u, u2) * side->tech[u2]) / 100;
  1215.         if (cross > side->tech[u2]) side->tech[u2] = cross;
  1216.     }
  1217.     }
  1218. }
  1219.  
  1220. /* Toolup action. */
  1221.  
  1222. /* Before a unit can build another, it may need to take some time to prepare by
  1223.    "tooling up". */
  1224.  
  1225. int
  1226. prep_toolup_action(unit, unit2, u3)
  1227. Unit *unit, *unit2;
  1228. int u3;
  1229. {
  1230.     if (unit == NULL || unit->act == NULL)
  1231.       return FALSE;
  1232.     if (unit2 == NULL)
  1233.       return FALSE;
  1234.     unit->act->nextaction.type = A_TOOL_UP;
  1235.     unit->act->nextaction.args[0] = u3;
  1236.     unit->act->nextaction.actee = unit2->id;
  1237.     return TRUE;
  1238. }
  1239.  
  1240. /* static */ int
  1241. do_toolup_action(unit, unit2, u3)
  1242. Unit *unit, *unit2;
  1243. int u3;
  1244. {
  1245.     int tp;
  1246.  
  1247.     if (unit2->tooling == NULL)
  1248.       init_unit_tooling(unit2);
  1249.     /* Increase the tooling, clipping to its max. */
  1250.     tp = unit2->tooling[u3];
  1251.     tp += uu_tp_per_toolup(unit2->type, u3);
  1252.     tp = min(tp, uu_tp_max(unit2->type, u3));
  1253.     unit2->tooling[u3] = tp;
  1254.     /* Adjust any related toolings. */
  1255.     adjust_tooling_crossover(unit2, u3);
  1256.     /* Consume acp. */
  1257.     use_up_acp(unit, uu_acp_to_toolup(unit2->type, u3));
  1258.     return A_ANY_DONE;
  1259. }
  1260.  
  1261. int
  1262. check_toolup_action(unit, unit2, u3)
  1263. Unit *unit, *unit2;
  1264. int u3;
  1265. {
  1266.     int acp, tp;
  1267.  
  1268.     if (!in_play(unit))
  1269.       return A_ANY_ERROR;
  1270.     if (!in_play(unit2))
  1271.       return A_ANY_ERROR;
  1272.     if (!is_unit_type(u3))
  1273.       return A_ANY_ERROR;
  1274.     acp = uu_acp_to_toolup(unit2->type, u3);
  1275.     if (acp < 1)
  1276.       return A_ANY_CANNOT_DO;
  1277.     if (!can_have_enough_acp(unit, acp))
  1278.       return A_ANY_CANNOT_DO;
  1279.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1280.     /* Check if tooling is already at its max. */
  1281.     if (tp >= uu_tp_max(unit2->type, u3))
  1282.       return A_ANY_ERROR;
  1283.     if (!has_enough_acp(unit, acp))
  1284.       return A_ANY_NO_ACP;
  1285.     return A_ANY_OK;
  1286. }
  1287.  
  1288. /* For all unit types, bring their tooling level up to match the crossovers
  1289.    from the given unit type. */
  1290.  
  1291. void
  1292. adjust_tooling_crossover(unit, u2)
  1293. Unit *unit;
  1294. int u2;
  1295. {
  1296.     int u3, uucross, cross, tp2, tp3;
  1297.  
  1298.     /* Perhaps nothing to cross over with. */
  1299.     if (unit->tooling == NULL)
  1300.       return;
  1301.     for_all_unit_types(u3) {
  1302.     if (u3 != u2) {
  1303.         uucross = uu_tp_crossover(u2, u3);
  1304.         if (uucross > 0) {
  1305.         tp2 = unit->tooling[u2];
  1306.         tp3 = unit->tooling[u3];
  1307.         /* (should be "as ratio of max levels for each type") */
  1308.         cross = (uucross * tp2) / 100;
  1309.         if (cross > tp3)
  1310.           unit->tooling[u3] = cross;
  1311.         }
  1312.     }
  1313.     }
  1314. }
  1315.  
  1316. /* Create-in action. */
  1317.  
  1318. /* This action creates the (incomplete) unit. */
  1319.  
  1320. void set_created_unit_props PROTO ((Unit *unit, int u2, Side *side));
  1321.  
  1322. int
  1323. prep_create_in_action(unit, unit2, u3, dest)
  1324. Unit *unit, *unit2, *dest;
  1325. int u3;
  1326. {
  1327.     if (unit == NULL || unit->act == NULL)
  1328.       return FALSE;
  1329.     if (unit2 == NULL)
  1330.       return FALSE;
  1331.     if (dest == NULL)
  1332.       return FALSE;
  1333.     unit->act->nextaction.type = A_CREATE_IN;
  1334.     unit->act->nextaction.args[0] = u3;
  1335.     unit->act->nextaction.args[1] = dest->id;
  1336.     unit->act->nextaction.actee = unit2->id;
  1337.     return TRUE;
  1338. }
  1339.  
  1340. /* static */ int
  1341. do_create_in_action(unit, unit2, u3, dest)
  1342. Unit *unit, *unit2, *dest;
  1343. int u3;
  1344. {
  1345.     int u = unit->type, u2 = unit2->type, m;
  1346.     Unit *newunit;
  1347.  
  1348.     /* Make the new unit. */
  1349.     newunit = create_unit(u3, FALSE);
  1350.     if (newunit != NULL) {
  1351.     /* Fill in various properties. */
  1352.     set_created_unit_props(newunit, u2, unit->side);
  1353.     /* Put the new unit inside the designated transport. */
  1354.     enter_transport(newunit, dest);
  1355.     /* Unit might have started out complete. */
  1356.     if (completed(newunit)) {
  1357.             garrison_unit(newunit, unit2);
  1358.         make_unit_complete(newunit);
  1359.     } else {
  1360.         record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
  1361.              side_number(unit2->side), newunit->id);
  1362.     }
  1363.     if (alive(unit2)) {
  1364.         /* Consume the creator's supplies as specified. */
  1365.         for_all_material_types(m) {
  1366.         unit2->supply[m] -= um_consumption_on_creation(u3, m);
  1367.         }
  1368.     }
  1369.     use_up_acp(unit, uu_acp_to_create(u2, u3));
  1370.     return A_ANY_DONE;
  1371.     } else {
  1372.     /* We've hit a max number of units, nothing to be done. */
  1373.     return A_ANY_ERROR;
  1374.     }
  1375. }
  1376.  
  1377. int
  1378. check_create_in_action(unit, unit2, u3, dest)
  1379. Unit *unit, *unit2, *dest;
  1380. int u3;
  1381. {
  1382.     int u, u2, m, tp;
  1383.  
  1384.     if (!in_play(unit))
  1385.       return A_ANY_ERROR;
  1386.     if (!in_play(unit2))
  1387.       return A_ANY_ERROR;
  1388.     if (!is_unit_type(u3))
  1389.       return A_ANY_ERROR;
  1390.     if (!in_play(dest))
  1391.       return A_ANY_ERROR;
  1392.     u = unit->type;  u2 = unit2->type;
  1393.     if (uu_acp_to_create(u2, u3) < 1)
  1394.       return A_ANY_CANNOT_DO;
  1395.     if (!can_have_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1396.       return A_ANY_CANNOT_DO;
  1397.     /* Check the tech level of the side. */
  1398.     if (u_tech_to_build(u3) > 0) {
  1399.     if (unit->side == NULL)
  1400.       return A_ANY_ERROR;
  1401.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1402.       return A_ANY_ERROR;
  1403.     }
  1404.     /* Check the tooling. */
  1405.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1406.     if (tp < uu_tp_to_build(u2, u3))
  1407.       return A_ANY_ERROR;
  1408.     if (distance(unit2->x, unit2->y, dest->x, dest->y) > uu_create_range(u2, u3))
  1409.       return A_ANY_TOO_FAR;
  1410.     if (unit2->transport != NULL
  1411.         && !uu_occ_can_build(unit2->transport->type, u2))
  1412.       return A_ANY_ERROR;
  1413.     if (!type_can_occupy(u3, dest))
  1414.       return A_ANY_ERROR;
  1415.     for_all_material_types(m) {
  1416.         if (unit2->supply[m] < um_to_create(u3, m))
  1417.           return A_ANY_NO_MATERIAL;
  1418.         if (unit2->supply[m] < um_consumption_on_creation(u3, m))
  1419.           return A_ANY_NO_MATERIAL;
  1420.     }
  1421.     if (!has_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1422.       return A_ANY_NO_ACP;
  1423.     return A_ANY_OK;
  1424. }
  1425.  
  1426. void
  1427. set_created_unit_props(newunit, u2, side)
  1428. Unit *newunit;
  1429. int u2;
  1430. Side *side;
  1431. {
  1432.     int u3 = newunit->type, m, amt;
  1433.  
  1434.     newunit->hp = newunit->hp2 = 1;
  1435.     newunit->cp = uu_creation_cp(u2, u3);
  1436.     if (unit_allowed_on_side(newunit, side))
  1437.       set_unit_side(newunit, side);
  1438.     /* Always number the unit when first created. */
  1439.     assign_unit_number(newunit);
  1440.     /* Set all supplies to their just-created levels. */
  1441.     for_all_material_types(m) {
  1442.     amt = newunit->supply[m];
  1443.     amt = max(amt, um_created_supply(u3, m));
  1444.     /* Clip to capacity. */
  1445.     amt = min(amt, um_storage_x(u3, m));
  1446.     newunit->supply[m] = amt;
  1447.     }
  1448. }
  1449.  
  1450. /* Create-at action. */
  1451.  
  1452. int
  1453. prep_create_at_action(unit, unit2, u3, x, y, z)
  1454. Unit *unit, *unit2;
  1455. int u3, x, y, z;
  1456. {
  1457.     if (unit == NULL || unit->act == NULL)
  1458.       return FALSE;
  1459.     if (unit2 == NULL)
  1460.       return FALSE;
  1461.     unit->act->nextaction.type = A_CREATE_AT;
  1462.     unit->act->nextaction.args[0] = u3;
  1463.     unit->act->nextaction.args[1] = x;
  1464.     unit->act->nextaction.args[2] = y;
  1465.     unit->act->nextaction.args[3] = z;
  1466.     unit->act->nextaction.actee = unit2->id;
  1467.     return TRUE;
  1468. }
  1469.  
  1470. /* static */ int
  1471. do_create_at_action(unit, unit2, u3, x, y, z)
  1472. Unit *unit, *unit2;
  1473. int u3, x, y, z;
  1474. {
  1475.     int u = unit->type, u2 = unit2->type, m;
  1476.     Unit *newunit;
  1477.  
  1478.     /* Make the new unit. */
  1479.     newunit = create_unit(u3, FALSE);
  1480.     if (newunit != NULL) {
  1481.     /* Fill in various properties. */
  1482.     set_created_unit_props(newunit, u2, unit->side);
  1483.     /* Put it at a correct location. */
  1484.     if (can_occupy_cell(newunit, x, y)) {
  1485.         enter_cell(newunit, x, y);
  1486.     } else if (can_occupy_cell_without(newunit, x, y, unit2)
  1487.            && can_occupy(unit2, newunit)) {
  1488.         /* Let the builder occupy its incomplete work. */
  1489.         leave_cell(unit2);
  1490.         enter_cell(newunit, x, y);
  1491.         enter_transport(unit2, newunit);
  1492.     } else {
  1493.         /* This should never happen. */
  1494.         run_error("construction/occupation complications");
  1495.     }
  1496.     /* and set its altitude? */
  1497.     /* Unit might be complete right away. */
  1498.     if (completed(newunit)) {
  1499.             garrison_unit(newunit, unit2);
  1500.         make_unit_complete(newunit);
  1501.     } else {
  1502.         record_event(H_UNIT_CREATED, add_side_to_set(unit2->side, NOSIDES),
  1503.              side_number(unit2->side), newunit->id);
  1504.     }
  1505.     if (alive(unit2)) {
  1506.         /* Consume the creator's supplies as specified. */
  1507.         for_all_material_types(m) {
  1508.         unit2->supply[m] -= um_consumption_on_creation(u3, m);
  1509.         }
  1510.     }
  1511.     use_up_acp(unit, uu_acp_to_create(u2, u3));
  1512.     return A_ANY_DONE;
  1513.     } else {
  1514.     /* We've hit a max number of units, nothing to be done. */
  1515.     return A_ANY_ERROR;
  1516.     }
  1517. }
  1518.  
  1519. int
  1520. check_create_at_action(unit, unit2, u3, x, y, z)
  1521. Unit *unit, *unit2;
  1522. int u3, x, y, z;
  1523. {
  1524.     int u, u2, m, tp;
  1525.  
  1526.     /* (should share code in create_in) */
  1527.     if (!in_play(unit))
  1528.       return A_ANY_ERROR;
  1529.     if (!in_play(unit2))
  1530.       return A_ANY_ERROR;
  1531.     if (!is_unit_type(u3))
  1532.       return A_ANY_ERROR;
  1533.     if (!inside_area(x, y))
  1534.       return A_ANY_ERROR;
  1535.     u = unit->type;  u2 = unit2->type;
  1536.     if (uu_acp_to_create(u2, u3) < 1)
  1537.       return A_ANY_CANNOT_DO;
  1538.     if (!can_have_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1539.       return A_ANY_CANNOT_DO;
  1540.     if (u_tech_to_build(u3) > 0) {
  1541.     if (unit->side == NULL)
  1542.       return A_ANY_ERROR;
  1543.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1544.       return A_ANY_ERROR;
  1545.     }
  1546.     if (distance(unit2->x, unit2->y, x, y) > uu_create_range(u2, u3))
  1547.       return A_ANY_TOO_FAR;
  1548.     /* Check the tooling. */
  1549.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1550.     if (tp < uu_tp_to_build(u2, u3))
  1551.       return A_ANY_ERROR;
  1552.     if (unit2->transport != NULL
  1553.         && !uu_occ_can_build(unit2->transport->type, u2))
  1554.       return A_ANY_ERROR;
  1555.     /* (should check for room and safety of terrain) */
  1556.     if (!(type_can_occupy_cell(u3, x, y)
  1557.           || (can_occupy_type(unit2, u3)
  1558.               && type_can_occupy_cell_without(u3, x, y, unit2))))
  1559.                 return A_ANY_ERROR;
  1560.     /* (should check that unit limit not hit yet) */
  1561.     for_all_material_types(m) {
  1562.         if (unit2->supply[m] < um_to_create(u3, m))
  1563.           return A_ANY_NO_MATERIAL;
  1564.         if (unit2->supply[m] < um_consumption_per_build(u3, m))
  1565.           return A_ANY_NO_MATERIAL;
  1566.     }
  1567.     if (!has_enough_acp(unit, uu_acp_to_create(u2, u3)))
  1568.       return A_ANY_NO_ACP;
  1569.     return A_ANY_OK;
  1570. }
  1571.  
  1572. /* Build action. */
  1573.  
  1574. /* This action makes progress on a construction effort, possibly completing
  1575.    the new unit and making it available. */
  1576.  
  1577. int
  1578. prep_build_action(unit, unit2, newunit)
  1579. Unit *unit, *unit2, *newunit;
  1580. {
  1581.     if (unit == NULL || unit->act == NULL)
  1582.       return FALSE;
  1583.     if (unit2 == NULL)
  1584.       return FALSE;
  1585.     unit->act->nextaction.type = A_BUILD;
  1586.     unit->act->nextaction.args[0] = newunit->id;
  1587.     unit->act->nextaction.actee = unit2->id;
  1588.     return TRUE;
  1589. }
  1590.  
  1591. /* static */ int
  1592. do_build_action(unit, unit2, newunit)
  1593. Unit *unit, *unit2, *newunit;
  1594. {
  1595.     int u, u2, u3, m, x, y;
  1596.     Unit *transp;
  1597.  
  1598.     u = unit->type;  u2 = unit2->type;  u3 = newunit->type;
  1599.     x = unit2->x;  y = unit2->y;
  1600.     transp = unit2->transport;
  1601.     for_all_material_types(m) {
  1602.         unit2->supply[m] -= um_consumption_per_build(u3, m);
  1603.     }
  1604.     newunit->cp += uu_cp_per_build(u2, u3);
  1605.     if (completed(newunit)) {
  1606.         garrison_unit(newunit, unit2);
  1607.     make_unit_complete(newunit);
  1608.     }
  1609.     update_unit_display(newunit->side, newunit, TRUE);
  1610.     use_up_acp(unit, uu_acp_to_build(u2, u3));
  1611.     return A_ANY_DONE;
  1612. }
  1613.  
  1614. void
  1615. garrison_unit(newunit, unit2)
  1616. Unit *newunit, *unit2;
  1617. {
  1618.     int u2 = unit2->type, u3 = newunit->type, x = unit2->x, y = unit2->y;
  1619.     Unit *transport = NULL, *occ;
  1620.  
  1621.     /* Maybe get rid of the building unit if it is to be the garrison. */
  1622.     if (uu_hp_to_garrison(u2, u3) >= unit2->hp) {
  1623.     /* But first get the about-to-be-killed garrisoning unit
  1624.        disconnected from everything. */
  1625.     leave_cell(unit2);
  1626.     /* Put new unit in place of the builder, if it was an occupant. */
  1627.     if (newunit->transport == unit2) {
  1628.         leave_transport(newunit);
  1629.         if (transport != NULL) { /* some other unit that could be transport? */
  1630.         enter_transport(newunit, transport);
  1631.         } else {
  1632.         enter_cell(newunit, x, y);
  1633.         }
  1634.     }
  1635.     /* Move the other occupants anywhere we can find. */
  1636.     for_all_occupants(unit2, occ) {
  1637.         if (can_occupy(occ, newunit)) {
  1638.         enter_transport(occ, newunit);
  1639.         } else if (transport != NULL && can_occupy(occ, transport)) {
  1640.         enter_transport(occ, transport);
  1641.         } else if (can_occupy_cell(occ, x, y)) {
  1642.         enter_cell(occ, x, y);
  1643.         }
  1644.         /* Otherwise the occupant has to die along with the garrison. */
  1645.         /* (should also do something with sub-occs of doomed occs?) */
  1646.     }
  1647.     /* Now we can get rid of the garrisoning unit without scrambling
  1648.        anything else. */
  1649.     kill_unit(unit2, H_UNIT_GARRISONED);
  1650.     } else {
  1651.     /* Builder just loses hp, doesn't vanish. */
  1652.     unit2->hp -= uu_hp_to_garrison(u2, u3);
  1653.     unit2->hp2 = unit2->hp;
  1654.     }
  1655. }
  1656.  
  1657. int
  1658. check_build_action(unit, unit2, newunit)
  1659. Unit *unit, *unit2, *newunit;
  1660. {
  1661.     int u, u2, u3, acpcost, m, tp;
  1662.  
  1663.     if (!in_play(unit))
  1664.       return A_ANY_ERROR;
  1665.     if (!in_play(unit2))
  1666.       return A_ANY_ERROR;
  1667.     if (!in_play(newunit))
  1668.       return A_ANY_ERROR;
  1669.     u = unit->type;
  1670.     u2 = unit2->type;
  1671.     u3 = newunit->type;
  1672.     acpcost = uu_acp_to_build(u2, u3);
  1673.     if (acpcost < 1)
  1674.       return A_ANY_CANNOT_DO;
  1675.     if (!can_have_enough_acp(unit, acpcost))
  1676.       return A_ANY_CANNOT_DO;
  1677.     /* Can't finish building a unit until we have the technology. */
  1678.     if (u_tech_to_build(u3) > 0) {
  1679.     if (unit->side == NULL)
  1680.       return A_ANY_ERROR;
  1681.     if (unit->side->tech[u3] < u_tech_to_build(u3))
  1682.       return A_ANY_ERROR;
  1683.     }
  1684.     /* Check the tooling. */
  1685.     tp = (unit2->tooling ? unit2->tooling[u3] : 0);
  1686.     if (tp < uu_tp_to_build(u2, u3))
  1687.       return A_ANY_ERROR;
  1688.     /* Check the distance to the unit being worked on. */
  1689.     if (distance(unit->x, unit->y, newunit->x, newunit->y)
  1690.     > uu_build_range(u, u3))
  1691.       return A_ANY_ERROR;
  1692.     /* Note that we should be able to build when inside the incomplete
  1693.        unit we're building. */
  1694.     if (unit2->transport != NULL
  1695.     && completed(unit2->transport)
  1696.         && !uu_occ_can_build(unit2->transport->type, u2))
  1697.       return A_ANY_ERROR;
  1698.     if (!has_enough_acp(unit, acpcost))
  1699.       return A_ANY_NO_ACP;
  1700.     for_all_material_types(m) {
  1701.         if (unit2->supply[m] < um_to_build(u2, m))
  1702.           return A_ANY_NO_MATERIAL;
  1703.         if (unit2->supply[m] < um_consumption_per_build(u3, m))
  1704.           return A_ANY_NO_MATERIAL;
  1705.     }
  1706.     return A_ANY_OK;
  1707. }
  1708.  
  1709. /* Do all the little things to make a fully operational unit. */
  1710.  
  1711. void
  1712. make_unit_complete(unit)
  1713. Unit *unit;
  1714. {
  1715.     int u = unit->type, m;
  1716.     SideMask observers;
  1717.     extern UnitVector *actionvector;
  1718.  
  1719.     /* Make this a "complete" but not a "fullsized" unit. */
  1720.     unit->cp = max(unit->cp, u_cp(u) / u_parts(u));
  1721.     unit->hp = unit->hp2 = u_hp(u) / u_parts(u);
  1722.     /* Christen our new unit. Its serial number (if it is a type that has
  1723.        one) was assigned just after its creation. */
  1724.     make_up_unit_name(unit);
  1725.     /* It also effectively starts viewing its surroundings. */
  1726.     if (unit->transport == NULL
  1727.     || uu_occ_can_see(unit->type, unit->transport->type)) {
  1728.     cover_area(unit->side, unit, unit->x, unit->y, 1);
  1729.     }
  1730.     /* Set all the supplies up to their unit-just-completed levels. */
  1731.     for_all_material_types(m) {
  1732.     unit->supply[m] = max(unit->supply[m], um_completed_supply(u, m));
  1733.     unit->supply[m] = min(unit->supply[m], um_storage_x(u, m));
  1734.     }
  1735.     init_unit_actorstate(unit);
  1736.     init_unit_plan(unit);
  1737.     /* Put this unit into action immediately, at full acp. */
  1738.     if (unit->act) {
  1739.     compute_acp(unit);
  1740.     if (unit->act->initacp > 0) {
  1741.         actionvector = add_unit_to_vector(actionvector, unit, 0);
  1742.     }
  1743.     }
  1744.     observers = add_side_to_set(unit->side, NOSIDES);
  1745.     /* (should add any other sides that might see this) */
  1746.     record_event(H_UNIT_COMPLETED, observers, side_number(unit->side), unit->id);
  1747.     /* (should add to any per-side tallies) */
  1748.     Dprintf("%s is completed\n", unit_desig(unit));
  1749. }
  1750.  
  1751. /* Repair action. */
  1752.  
  1753. int
  1754. prep_repair_action(unit, unit2, unit3)
  1755. Unit *unit, *unit2, *unit3;
  1756. {
  1757.     if (unit == NULL || unit->act == NULL)
  1758.       return FALSE;
  1759.     if (unit2 == NULL)
  1760.       return FALSE;
  1761.     if (unit3 == NULL)
  1762.       return FALSE;
  1763.     unit->act->nextaction.type = A_REPAIR;
  1764.     unit->act->nextaction.args[0] = unit3->id;
  1765.     unit->act->nextaction.actee = unit2->id;
  1766.     return TRUE;
  1767. }
  1768.  
  1769. /* static */ int
  1770. do_repair_action(unit, unit2, unit3)
  1771. Unit *unit, *unit2, *unit3;
  1772. {
  1773.     int u, u2, u3, rep, m;
  1774.  
  1775.     u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
  1776.     rep = uu_repair(u2, u3);
  1777.     /* Add to the repairee's hit points. */
  1778.     unit3->hp += prob_fraction(rep);
  1779.     unit3->hp2 = unit3->hp;
  1780.     /* Eat supplies used up by repair. */
  1781.     for_all_material_types(m) {
  1782.     unit2->supply[m] -= um_consumption_per_repair(u3, m);
  1783.     }
  1784.     use_up_acp(unit, uu_acp_to_repair(u2, u3));
  1785.     return A_ANY_DONE;
  1786. }
  1787.  
  1788. int
  1789. check_repair_action(unit, unit2, unit3)
  1790. Unit *unit, *unit2, *unit3;
  1791. {
  1792.     int u, u2, u3, acp, m;
  1793.  
  1794.     if (!in_play(unit))
  1795.       return A_ANY_ERROR;
  1796.     if (!in_play(unit2))
  1797.       return A_ANY_ERROR;
  1798.     if (!in_play(unit3))
  1799.       return A_ANY_ERROR;
  1800.     u = unit->type;  u2 = unit2->type;  u3 = unit3->type;
  1801.     acp = uu_acp_to_repair(u2, u3);
  1802.     if (acp < 1)
  1803.       return A_ANY_CANNOT_DO;
  1804.     if (!can_have_enough_acp(unit, acp))
  1805.       return A_ANY_CANNOT_DO;
  1806.     if (uu_repair(u2, u3) <= 0)
  1807.       return A_ANY_ERROR;
  1808.     if (unit3->hp >= u_hp(u3))
  1809.       return A_ANY_ERROR;
  1810.     if (unit2->hp < uu_hp_to_repair(u2, u3))
  1811.       return A_ANY_ERROR;
  1812.     for_all_material_types(m) {
  1813.     if (unit2->supply[m] < um_to_repair(u2, m))
  1814.       return A_ANY_NO_MATERIAL;
  1815.     if (unit2->supply[m] < um_consumption_per_repair(u3, m))
  1816.       return A_ANY_NO_MATERIAL;
  1817.     }
  1818.     if (!has_enough_acp(unit, acp))
  1819.       return A_ANY_NO_ACP;
  1820.     return A_ANY_OK;
  1821. }
  1822.  
  1823. /* Disband action. */
  1824.  
  1825. /* The disband action destroys a unit in an "orderly" fashion, and can be
  1826.    undertaken voluntarily. */
  1827.  
  1828. int
  1829. prep_disband_action(unit, unit2)
  1830. Unit *unit, *unit2;
  1831. {
  1832.     if (unit == NULL || unit->act == NULL)
  1833.       return FALSE;
  1834.     if (unit2 == NULL)
  1835.       return FALSE;
  1836.     unit->act->nextaction.type = A_DISBAND;
  1837.     unit->act->nextaction.actee = unit2->id;
  1838.     return TRUE;
  1839. }
  1840.  
  1841. /* static */ int
  1842. do_disband_action(unit, unit2)
  1843. Unit *unit, *unit2;
  1844. {
  1845.     int u2, m, amt, disb;
  1846.  
  1847.     u2 = unit2->type;
  1848.     /* Recover some percentage of the unit's supply. */
  1849.     for_all_material_types(m) {
  1850.         if (um_supply_per_disband(u2, m) > 0 && unit2->supply[m] > 0) {
  1851.             amt = (unit2->supply[m] * um_supply_per_disband(u2, m)) / 100;
  1852.             /* Unit always loses the amount, whether or not distributed. */
  1853.             unit2->supply[m] -= amt;
  1854.             distribute_material(unit2, m, amt);
  1855.         }
  1856.     }
  1857.     /* Remove hit points or kill the unit directly. */
  1858.     disb = u_hp_per_disband(u2);
  1859.     if (disb < unit2->hp) {
  1860.     unit2->hp -= disb;
  1861.     unit2->hp2 = unit2->hp;
  1862.     } else {
  1863.         /* Pass around whatever we can get out of the unit itself. */
  1864.         for_all_material_types(m) {
  1865.             if (um_recycleable(u2, m) > 0) {
  1866.                 distribute_material(unit2, m, um_recycleable(u2, m));
  1867.             }
  1868.         }
  1869.         /* should ensure vanish */
  1870.     kill_unit(unit2, H_UNIT_DISBANDED);
  1871.     }
  1872.     use_up_acp(unit, u_acp_to_disband(u2));
  1873.     return A_ANY_DONE;
  1874. }
  1875.  
  1876. /* Given a unit and a quantity of material, pass it out to nearby units. */
  1877.  
  1878. void
  1879. distribute_material(unit, m, amt)
  1880. Unit *unit;
  1881. int m, amt;
  1882. {
  1883.     /* Distribute to transport first. */
  1884.     if (amt > 0 && unit->transport != NULL) {
  1885.         /* (should clip to capacity etc) */
  1886.         unit->transport->supply[m] += amt;
  1887.         amt = 0;
  1888.     }
  1889.     /* Then to any unit in the cell. */
  1890.     if (amt > 0) {
  1891.     }
  1892.     /* Then to any unit in an adjacent cell. */
  1893.     if (amt > 0) {
  1894.     }
  1895.     /* (should note anything that went to waste?) */
  1896. }
  1897.  
  1898. int
  1899. check_disband_action(unit, unit2)
  1900. Unit *unit, *unit2;
  1901. {
  1902.     int u, u2, acp;
  1903.  
  1904.     if (!in_play(unit))
  1905.       return A_ANY_ERROR;
  1906.     if (!in_play(unit2))
  1907.       return A_ANY_ERROR;
  1908.     u = unit->type;  u2 = unit->type;
  1909.     acp = u_acp_to_disband(u2);
  1910.     if (acp < 1)
  1911.       return A_ANY_CANNOT_DO;
  1912.     if (!can_have_enough_acp(unit, acp))
  1913.       return A_ANY_CANNOT_DO;
  1914.     if (u_hp_per_disband(unit2->type) <= 0)
  1915.       return A_ANY_ERROR; /* should warn instead */
  1916.     if (!has_enough_acp(unit, acp))
  1917.       return A_ANY_NO_ACP;
  1918.     return A_ANY_OK;
  1919. }
  1920.  
  1921. /* Transfer-part action. */
  1922.  
  1923. /* Create a new unit that is similar to the original one, and give it
  1924.    some of the parts of the original unit. */
  1925. /* (New unit in same cell if possible or else in random adjacent cell.) */
  1926.  
  1927. int
  1928. prep_transfer_part_action(unit, unit2, parts, unit3)
  1929. Unit *unit, *unit2, *unit3;
  1930. int parts;
  1931. {
  1932.     if (unit == NULL || unit->act == NULL)
  1933.       return FALSE;
  1934.     if (unit2 == NULL)
  1935.       return FALSE;
  1936.     unit->act->nextaction.type = A_TRANSFER_PART;
  1937.     unit->act->nextaction.args[0] = parts;
  1938.     unit->act->nextaction.args[1] = (unit3 ? unit3->id : 0);
  1939.     unit->act->nextaction.actee = unit2->id;
  1940.     return TRUE;
  1941. }
  1942.  
  1943. /* static */ int
  1944. do_transfer_part_action(unit, unit2, parts, unit3)
  1945. Unit *unit, *unit2, *unit3;
  1946. int parts;
  1947. {
  1948.     int u2 = unit2->type, acp, part_hp;
  1949.  
  1950.     part_hp = u_hp(u2) / u_parts(u2);
  1951.     if (unit3 == NULL) {
  1952.     /* Create a new unit with parts from unit2. */
  1953.     unit3 = create_unit(u2, TRUE);
  1954.     if (unit3 != NULL) {
  1955.         unit3->hp = parts * part_hp;
  1956.         /* (Cap the hp now - occupancy calcs below might use unit parts
  1957.             to determine available capacity) */
  1958.         unit3->hp = min(unit3->hp, u_hp(unit3->type));
  1959.         unit3->hp2 = unit3->hp;
  1960.         if (unit_allowed_on_side(unit3, unit->side))
  1961.           set_unit_side(unit3, unit->side);
  1962.         /* Always number the unit when first created. */
  1963.         assign_unit_number(unit3);
  1964.         /* (should fill in more slots of new unit, such as supply?) */
  1965.         if (can_occupy_cell(unit3, unit2->x, unit2->y)) {
  1966.         enter_cell(unit3, unit2->x, unit2->y);
  1967.         } else {
  1968.             /* (should add code to enter something else here) */
  1969.         /* This should never happen. */
  1970.         run_warning("transfer_part complications, leaving unit offworld");
  1971.         }
  1972.     } else {
  1973.         /* We have a problem. */
  1974.         return A_ANY_ERROR;
  1975.     }
  1976.     } else {
  1977.     /* Increase the unit3's hp by what's in this unit, and cap it. */
  1978.     unit3->hp += parts * part_hp;
  1979.     /* Should affect morale etc according to proportions of mixing */
  1980.     unit3->hp = min(unit3->hp, u_hp(unit3->type));
  1981.     unit3->hp2 = unit3->hp;
  1982.     }
  1983.     /* Need to tweak parts in unit2 also */
  1984.     if (parts * part_hp >= unit2->hp) {
  1985.     /* (should transfer occs to unit3) */
  1986.     kill_unit(unit2, -1);  /* should add a merge kill-reason */
  1987.     } else {
  1988.     unit2->hp -= parts * part_hp;
  1989.     unit2->hp2 = unit2->hp;
  1990.     }
  1991.     if (alive(unit2))
  1992.       update_unit_display(unit2->side, unit2, TRUE);
  1993.     update_unit_display(unit3->side, unit3, TRUE);
  1994.     acp = u_acp_to_transfer_part(u2);
  1995.     use_up_acp(unit, acp);
  1996.     return A_ANY_DONE;
  1997. }
  1998.  
  1999. int
  2000. check_transfer_part_action(unit, unit2, parts, unit3)
  2001. Unit *unit, *unit2, *unit3;
  2002. int parts;
  2003. {
  2004.     int u2, acp;
  2005.  
  2006.     if (!in_play(unit))
  2007.       return A_ANY_ERROR;
  2008.     if (!in_play(unit2))
  2009.       return A_ANY_ERROR;
  2010.     if (parts <= 0)
  2011.       return A_ANY_ERROR;
  2012.     /* unit3 can be null. */
  2013.     u2 = unit2->type;
  2014.     acp = u_acp_to_transfer_part(u2);
  2015.     if (acp < 1)
  2016.       return A_ANY_CANNOT_DO;
  2017.     if (!can_have_enough_acp(unit, acp))
  2018.       return A_ANY_CANNOT_DO;
  2019.     if (u_parts(u2) <= 1)
  2020.       return A_ANY_ERROR;
  2021.     if (!has_enough_acp(unit, acp))
  2022.       return A_ANY_NO_ACP;
  2023.     return A_ANY_OK;
  2024. }
  2025.  
  2026. /* Change-type action. */
  2027.  
  2028. int
  2029. prep_change_type_action(unit, unit2, u3)
  2030. Unit *unit, *unit2;
  2031. int u3;
  2032. {
  2033.     if (unit == NULL || unit->act == NULL)
  2034.       return FALSE;
  2035.     if (unit2 == NULL)
  2036.       return FALSE;
  2037.     unit->act->nextaction.type = A_CHANGE_TYPE;
  2038.     unit->act->nextaction.args[0] = u3;
  2039.     unit->act->nextaction.actee = unit2->id;
  2040.     return TRUE;
  2041. }
  2042.  
  2043. /* Actually change the type of a unit. */
  2044.  
  2045. /* static */ int
  2046. do_change_type_action(unit, unit2, u3)
  2047. Unit *unit, *unit2;
  2048. int u3;
  2049. {
  2050.     int u, u2;
  2051.  
  2052.     u = unit->type;
  2053.     u2 = unit2->type;
  2054.     change_unit_type(unit2, u3, H_UNIT_TYPE_CHANGED);
  2055.     update_unit_display(unit2->side, unit2, TRUE);
  2056.     /* (should consume materials) */
  2057.     use_up_acp(unit, uu_acp_to_change_type(u2, u3));
  2058.     return A_ANY_DONE;
  2059. }
  2060.  
  2061. int
  2062. check_change_type_action(unit, unit2, u3)
  2063. Unit *unit, *unit2;
  2064. int u3;
  2065. {
  2066.     int u, u2, acp, m;
  2067.  
  2068.     if (!in_play(unit))
  2069.       return A_ANY_ERROR;
  2070.     if (!in_play(unit2))
  2071.       return A_ANY_ERROR;
  2072.     if (!is_unit_type(u3))
  2073.       return A_ANY_ERROR;
  2074.     u = unit->type;
  2075.     u2 = unit2->type;
  2076.     acp = uu_acp_to_change_type(u2, u3);
  2077.     if (acp < 1)
  2078.       return A_ANY_CANNOT_DO;
  2079.     if (!can_have_enough_acp(unit, acp))
  2080.       return A_ANY_CANNOT_DO;
  2081.     /* should check if still on allowable side */
  2082.     if (!has_enough_acp(unit, acp))
  2083.       return A_ANY_NO_ACP;
  2084.     /* Check that the unit has any required supplies. */
  2085.     for_all_material_types(m) {
  2086.     if (unit2->supply[m] < um_to_change_type(u2, m))
  2087.       return A_ANY_NO_MATERIAL;
  2088.     }
  2089.     return A_ANY_OK;
  2090. }
  2091.  
  2092. /* Change-side action. */
  2093.  
  2094. /* Tell a unit to change to a given side. */
  2095.  
  2096. /* (what about occs, garrisons, plans?) */
  2097.  
  2098. int
  2099. prep_change_side_action(unit, unit2, side)
  2100. Unit *unit, *unit2;
  2101. Side *side;
  2102. {
  2103.     if (unit == NULL || unit->act == NULL)
  2104.       return FALSE;
  2105.     if (unit2 == NULL)
  2106.       return FALSE;
  2107.     unit->act->nextaction.type = A_CHANGE_SIDE;
  2108.     unit->act->nextaction.args[0] = side_number(side);
  2109.     unit->act->nextaction.actee = unit2->id;
  2110.     return TRUE;
  2111. }
  2112.  
  2113. /* static */ int
  2114. do_change_side_action(unit, unit2, side)
  2115. Unit *unit, *unit2;
  2116. Side *side;
  2117. {
  2118.     int rslt;
  2119.  
  2120.     if (side_controls_unit(unit->side, unit2)) {
  2121.     /* If we own it, we can just change it. */
  2122.     unit_changes_side(unit2, side, -1, -1);
  2123.     rslt = A_ANY_DONE;
  2124.     } else {
  2125.     rslt = A_ANY_ERROR;
  2126.     }
  2127.     use_up_acp(unit, u_acp_to_change_side(unit2->type));
  2128.     return rslt;
  2129. }
  2130.  
  2131. int
  2132. check_change_side_action(unit, unit2, side)
  2133. Unit *unit, *unit2;
  2134. Side *side;
  2135. {
  2136.     int u, u2, acp;
  2137.  
  2138.     if (!in_play(unit))
  2139.       return A_ANY_ERROR;
  2140.     if (!in_play(unit2))
  2141.       return A_ANY_ERROR;
  2142.     if (!side_in_play(side))
  2143.       return A_ANY_ERROR;
  2144.     if (unit2->side == side)
  2145.       return A_ANY_ERROR;
  2146.     if (!unit_allowed_on_side(unit2, side))
  2147.       return A_ANY_ERROR;
  2148.     u = unit->type;
  2149.     u2 = unit2->type;
  2150.     acp = u_acp_to_change_side(u2);
  2151.     if (acp < 1)
  2152.       return A_ANY_CANNOT_DO;
  2153.     if (!can_have_enough_acp(unit, acp))
  2154.       return A_ANY_CANNOT_DO;
  2155.     if (!has_enough_acp(unit, acp))
  2156.       return A_ANY_NO_ACP;
  2157.     return A_ANY_OK;
  2158. }
  2159.  
  2160. /* Alter-terrain action. */
  2161.  
  2162. /* Change the terrain in the cell to something else. */
  2163.  
  2164. /* We don't need to ensure that the unit can exist on the new terrain
  2165.    type, because the designer is presumed to have set things up sensibly,
  2166.    because the unit might be in an appropriate transport, or because
  2167.    there is some actual use in such a bizarre shtick. */
  2168.  
  2169. /* What if engineers dig hole underneath enemy unit?  Should this be
  2170.    possible, or should there be a "can-dig-under-enemy" parm?  */
  2171.  
  2172. int
  2173. prep_alter_cell_action(unit, unit2, x, y, t)
  2174. Unit *unit, *unit2;
  2175. int x, y, t;
  2176. {
  2177.     if (unit == NULL || unit->act == NULL)
  2178.       return FALSE;
  2179.     if (unit2 == NULL)
  2180.       return FALSE;
  2181.     unit->act->nextaction.type = A_ALTER_TERRAIN;
  2182.     unit->act->nextaction.args[0] = x;
  2183.     unit->act->nextaction.args[1] = y;
  2184.     unit->act->nextaction.args[2] = t;
  2185.     unit->act->nextaction.actee = unit2->id;
  2186.     return TRUE;
  2187. }
  2188.  
  2189. /* static */ int
  2190. do_alter_cell_action(unit, unit2, x, y, t)
  2191. Unit *unit, *unit2;
  2192. int x, y, t;
  2193. {
  2194.     int u, u2, oldt, acpr, acpa, rslt;
  2195.     Side *side;
  2196.  
  2197.     u = unit->type;  u2 = unit2->type;
  2198.     oldt = terrain_at(x, y);
  2199.     /* Change the terrain to the new type. */
  2200.     set_terrain_at(x, y, t);
  2201.     /* Let everybody see what has happened. */
  2202.     if (t != oldt) {
  2203.     for_all_sides(side) {
  2204.             if (g_see_all() || g_see_terrain_always() || side == unit->side) {
  2205.         update_cell_display(side, x, y, TRUE);
  2206.             }
  2207.     }
  2208.     }
  2209.     /* Note that we still charge acp even if terrain type doesn't change. */
  2210.     acpr = ut_acp_to_remove_terrain(u2, oldt);
  2211.     acpa = ut_acp_to_add_terrain(u2, t);
  2212.     use_up_acp(unit, acpr + acpa);
  2213.     return A_ANY_DONE;
  2214. }
  2215.  
  2216. int
  2217. check_alter_cell_action(unit, unit2, x, y, t)
  2218. Unit *unit, *unit2;
  2219. int x, y, t;
  2220. {
  2221.     int u, u2, oldt, acpr, acpa;
  2222.  
  2223.     if (!in_play(unit))
  2224.       return A_ANY_ERROR;
  2225.     if (!in_play(unit2))
  2226.       return A_ANY_ERROR;
  2227.     if (!in_area(x, y))
  2228.       return A_ANY_ERROR;
  2229.     if (!is_terrain_type(t))
  2230.       return A_ANY_ERROR;
  2231.     if (!t_is_cell(t))
  2232.       return A_ANY_ERROR;
  2233.     u = unit->type;
  2234.     u2 = unit2->type;
  2235.     oldt = terrain_at(x, y);
  2236.     acpr = ut_acp_to_remove_terrain(u2, oldt);
  2237.     acpa = ut_acp_to_add_terrain(u2, t);
  2238.     if (acpr < 1 || acpa < 1)
  2239.       return A_ANY_CANNOT_DO;
  2240.     if (!can_have_enough_acp(unit, acpr + acpa))
  2241.       return A_ANY_CANNOT_DO;
  2242.     if (distance(unit2->x, unit2->y, x, y) > ut_alter_range(u2, t))
  2243.       return A_ANY_ERROR;
  2244.     if (!has_enough_acp(unit, acpr + acpa))
  2245.       return A_ANY_NO_ACP;
  2246.     return A_ANY_OK;
  2247. }
  2248.  
  2249. /* Add-terrain action. */
  2250.  
  2251. /* Add terrain; border, connection, or coating. */
  2252.  
  2253. int
  2254. prep_add_terrain_action(unit, unit2, x, y, dir, t)
  2255. Unit *unit, *unit2;
  2256. int x, y, dir, t;
  2257. {
  2258.     if (unit == NULL || unit->act == NULL)
  2259.       return FALSE;
  2260.     if (unit2 == NULL)
  2261.       return FALSE;
  2262.     unit->act->nextaction.type = A_ADD_TERRAIN;
  2263.     unit->act->nextaction.args[0] = x;
  2264.     unit->act->nextaction.args[1] = y;
  2265.     unit->act->nextaction.args[2] = dir;
  2266.     unit->act->nextaction.args[3] = t;
  2267.     unit->act->nextaction.actee = unit2->id;
  2268.     return TRUE;
  2269. }
  2270.  
  2271. /* static */ int
  2272. do_add_terrain_action(unit, unit2, x, y, dir, t)
  2273. Unit *unit, *unit2;
  2274. int x, y, dir, t;
  2275. {
  2276.     int u = unit->type, oldval, newval, x1, y1;
  2277.     Side *side;
  2278.  
  2279.     switch (t_subtype(t)) {
  2280.       case cellsubtype:
  2281.           /* Will never happen. */
  2282.           break;
  2283.       case bordersubtype:
  2284.           oldval = border_at(x, y, dir, t);
  2285.           newval = TRUE;
  2286.     set_border_at(x, y, dir, t, newval);
  2287.           break;
  2288.       case connectionsubtype:
  2289.           oldval = connection_at(x, y, dir, t);
  2290.           newval = TRUE;
  2291.     set_connection_at(x, y, dir, t, newval);
  2292.           break;
  2293.       case coatingsubtype:
  2294.         oldval = aux_terrain_at(x, y, t);
  2295.           /* Interpret "dir" as depth of coating to add. */
  2296.         newval = min(oldval + dir, tt_coat_max(terrain_at(x, y), t));
  2297.         set_aux_terrain_at(x, y, t, newval);
  2298.           break;
  2299.     }
  2300.     /* Let everybody see what has happened. */
  2301.     if (newval != oldval) {
  2302.       for_all_sides(side) {
  2303.         if (g_see_all() || g_see_terrain_always() || side == unit->side) {
  2304.             update_cell_display(side, x, y, TRUE);
  2305.             if (t_subtype(t) != coatingsubtype) {
  2306.         if (point_in_dir(x, y, dir, &x1, &y1))
  2307.           update_cell_display(side, x1, y1, TRUE);
  2308.             }
  2309.         }
  2310.       }
  2311.     }
  2312.     use_up_acp(unit, (newval != oldval ? ut_acp_to_add_terrain(u, t) : 1));
  2313.     return A_ANY_DONE;
  2314. }
  2315.  
  2316. int
  2317. check_add_terrain_action(unit, unit2, x, y, dir, t)
  2318. Unit *unit, *unit2;
  2319. int x, y, dir, t;
  2320. {
  2321.     int u, u2, acp;
  2322.  
  2323.     if (!in_play(unit))
  2324.       return A_ANY_ERROR;
  2325.     if (!in_play(unit2))
  2326.       return A_ANY_ERROR;
  2327.     if (!inside_area(x, y))
  2328.       return A_ANY_ERROR;
  2329.     /* should check dir also? */
  2330.     if (!is_terrain_type(t))
  2331.       return A_ANY_ERROR;
  2332.     if (t_is_cell(t))
  2333.       return A_ANY_ERROR;
  2334.     u = unit->type;
  2335.     u2 = unit2->type;
  2336.     acp = ut_acp_to_add_terrain(u2, t);
  2337.     if (acp < 1)
  2338.       return A_ANY_CANNOT_DO;
  2339.      if (!can_have_enough_acp(unit, acp))
  2340.        return A_ANY_CANNOT_DO;
  2341.    if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
  2342.       return A_ANY_ERROR;
  2343.     if (!has_enough_acp(unit, acp))
  2344.       return A_ANY_NO_ACP;
  2345.     return A_ANY_OK;
  2346. }
  2347.  
  2348. /* Remove-terrain action. */
  2349.  
  2350. /* Remove a border, connection, or coating. */
  2351.  
  2352. int
  2353. prep_remove_terrain_action(unit, unit2, x, y, dir, t)
  2354. Unit *unit, *unit2;
  2355. int x, y, dir, t;
  2356. {
  2357.     if (unit == NULL || unit->act == NULL)
  2358.       return FALSE;
  2359.     if (unit2 == NULL)
  2360.       return FALSE;
  2361.     unit->act->nextaction.type = A_REMOVE_TERRAIN;
  2362.     unit->act->nextaction.args[0] = x;
  2363.     unit->act->nextaction.args[1] = y;
  2364.     unit->act->nextaction.args[2] = dir;
  2365.     unit->act->nextaction.args[3] = t;
  2366.     unit->act->nextaction.actee = unit2->id;
  2367.     return TRUE;
  2368. }
  2369.  
  2370. /* static */ int
  2371. do_remove_terrain_action(unit, unit2, x, y, dir, t)
  2372. Unit *unit, *unit2;
  2373. int x, y, dir, t;
  2374. {
  2375.     int u = unit->type, oldval, newval, x1, y1;
  2376.     Side *side;
  2377.  
  2378.     switch (t_subtype(t)) {
  2379.       case cellsubtype:
  2380.           /* Will never happen. */
  2381.           break;
  2382.       case bordersubtype:
  2383.     oldval = border_at(x, y, dir, t);
  2384.     newval = FALSE;
  2385.     set_border_at(x, y, dir, t, newval);
  2386.           break;
  2387.       case connectionsubtype:
  2388.     oldval = connection_at(x, y, dir, t);
  2389.     newval = FALSE;
  2390.     set_connection_at(x, y, dir, t, newval);
  2391.           break;
  2392.       case coatingsubtype:
  2393.         oldval = aux_terrain_at(x, y, t);
  2394.            /* Interpret "dir" as depth of coating to remove. */
  2395.        newval = max(oldval - dir, 0);
  2396.        /* If newval drops below the min coating depth, coating will vanish. */
  2397.         if (newval < tt_coat_min(terrain_at(x, y), t))
  2398.           newval = 0;
  2399.         set_aux_terrain_at(x, y, t, newval);
  2400.           break;
  2401.     }
  2402.     /* Let everybody see what has happened. */
  2403.     for_all_sides(side) {
  2404.         if (g_see_all() || g_see_terrain_always() || side == unit->side) {
  2405.             update_cell_display(side, x, y, TRUE);
  2406.             if (t_subtype(t) != coatingsubtype) {
  2407.         if (point_in_dir(x, y, dir, &x1, &y1))
  2408.           update_cell_display(side, x1, y1, TRUE);
  2409.             }
  2410.         }
  2411.     }
  2412.     use_up_acp(unit, ut_acp_to_remove_terrain(u, t));
  2413.     return A_ANY_DONE;
  2414. }
  2415.  
  2416. int
  2417. check_remove_terrain_action(unit, unit2, x, y, dir, t)
  2418. Unit *unit, *unit2;
  2419. int x, y, dir, t;
  2420. {
  2421.     int u, u2, acp;
  2422.  
  2423.     if (!in_play(unit))
  2424.       return A_ANY_ERROR;
  2425.     if (!in_play(unit2))
  2426.       return A_ANY_ERROR;
  2427.     if (!inside_area(x, y))
  2428.       return A_ANY_ERROR;
  2429.     /* should check dir also? */
  2430.     if (!is_terrain_type(t))
  2431.       return A_ANY_ERROR;
  2432.     if (t_is_cell(t))
  2433.       return A_ANY_ERROR;
  2434.     u = unit->type;
  2435.     u2 = unit2->type;
  2436.     acp = ut_acp_to_remove_terrain(u2, t);
  2437.     if (acp < 1)
  2438.       return A_ANY_CANNOT_DO;
  2439.     if (!can_have_enough_acp(unit, acp))
  2440.       return A_ANY_CANNOT_DO;
  2441.     if (distance(unit->x, unit->y, x, y) > ut_alter_range(u2, t))
  2442.       return A_ANY_ERROR;
  2443.     if (!has_enough_acp(unit, acp))
  2444.       return A_ANY_NO_ACP;
  2445.     return A_ANY_OK;
  2446. }
  2447.  
  2448. /* Execute a given action on a given unit. */
  2449.  
  2450. /* (assumes unit can act in the first place - valid?) */
  2451.  
  2452. int
  2453. execute_action(unit, action)
  2454. Unit *unit;
  2455. Action *action;
  2456. {
  2457.     char *argtypestr;
  2458.     int u = unit->type, rslt = A_ANY_ERROR, n, i;
  2459.     long args[4];
  2460.     Unit *unit2, *argunit;
  2461.     Side *argside, *side2;
  2462. #ifdef THINK_C
  2463.     /* Think C can be excessively picky sometimes. */
  2464.     int (*checkfn) PROTO ((Unit *unit, Unit *unit2, ...));
  2465.     int (*dofn) PROTO ((Unit *unit, Unit *unit2, ...));
  2466. #else
  2467.     int (*checkfn) ();
  2468.     int (*dofn) ();
  2469. #endif
  2470.     extern int numsoundplays;
  2471.  
  2472.     Dprintf("%s doing %s with %d acp left\n",
  2473.         unit_desig(unit), action_desig(action), unit->act->acp);
  2474.  
  2475.     if (!alive(unit) || !unit->act || unit->act->acp < u_acp_min(u))
  2476.       return A_ANY_ERROR;
  2477.  
  2478.     argtypestr = actiondefns[(int) action->type].argtypes;
  2479.     n = strlen(argtypestr);
  2480.     for (i = 0; i < n; ++i) {
  2481.     switch (argtypestr[i]) {
  2482.       case 'n':
  2483.       case 'u':
  2484.       case 'm':
  2485.       case 't':
  2486.       case 'x':
  2487.       case 'y':
  2488.       case 'z':
  2489.       case 'd':
  2490.         args[i] = action->args[i];
  2491.         break;
  2492.       case 'U':
  2493.         argunit = find_unit(action->args[i]);
  2494.         if (argunit == NULL) {
  2495.         /* an error, should do run_warning */
  2496.         }
  2497.         args[i] = (long) argunit;
  2498.         break;
  2499.       case 'S':
  2500.         argside = side_n(action->args[i]);
  2501.         args[i] = (long) argside;
  2502.         break;
  2503.       default:
  2504.         /* should warn */
  2505.         break;
  2506.     }
  2507.     }
  2508.     checkfn = actiondefns[(int) action->type].checkfn;
  2509.     dofn = actiondefns[(int) action->type].dofn;
  2510.     if (action->actee == 0) {
  2511.     unit2 = unit;
  2512.     } else {
  2513.     unit2 = find_unit(action->actee);
  2514.     }
  2515.     if (unit2 == NULL) {
  2516.     return A_ANY_ERROR;
  2517.     }
  2518.     switch (n) {
  2519.       case 0:
  2520.     rslt = (*checkfn)(unit, unit2);
  2521.     break;
  2522.       case 1:
  2523.     rslt = (*checkfn)(unit, unit2, args[0]);
  2524.     break;
  2525.       case 2:
  2526.     rslt = (*checkfn)(unit, unit2, args[0], args[1]);
  2527.     break;
  2528.       case 3:
  2529.     rslt = (*checkfn)(unit, unit2, args[0], args[1], args[2]);
  2530.     break;
  2531.       case 4:
  2532.     rslt = (*checkfn)(unit, unit2, args[0], args[1], args[2], args[3]);
  2533.     break;
  2534.       default:
  2535.     case_panic("action arg count", n);
  2536.     }
  2537.     numsoundplays = 0; /* kind of a hack */
  2538.     if (valid(rslt)) {
  2539.     if (g_action_messages() != lispnil)
  2540.       play_action_messages(unit, action);
  2541.     switch (n) {
  2542.       case 0:
  2543.         rslt = (*dofn)(unit, unit2);
  2544.         break;
  2545.       case 1:
  2546.         rslt = (*dofn)(unit, unit2, args[0]);
  2547.         break;
  2548.       case 2:
  2549.         rslt = (*dofn)(unit, unit2, args[0], args[1]);
  2550.         break;
  2551.       case 3:
  2552.         rslt = (*dofn)(unit, unit2, args[0], args[1], args[2]);
  2553.         break;
  2554.       case 4:
  2555.         rslt = (*dofn)(unit, unit2, args[0], args[1], args[2], args[3]);
  2556.         break;
  2557.       default:
  2558.         case_panic("action arg count", n);
  2559.     }
  2560.     Dprintf("%s action %s result is %s, %d acp left\n",
  2561.         unit_desig(unit), action_desig(action), hevtdefns[rslt].name,
  2562.         (unit->act ? unit->act->acp : -9999));
  2563.     if (unit->plan) {
  2564.         unit->plan->lastaction = *action;
  2565.         unit->plan->lastresult = rslt;
  2566.     }
  2567.     if (unit->side && side_has_ai(unit->side)) {
  2568.         ai_react_to_action_result(unit->side, unit, rslt);
  2569.     }
  2570.     if (unit->side && side_has_display(unit->side)) {
  2571.         update_action_result_display(unit->side, unit, rslt, TRUE);
  2572.     }
  2573.     /* Show other sides that some action has occurred. */
  2574.     for_all_sides(side2) {
  2575.         if (side_has_display(side2)) {
  2576.         update_side_display(side2, unit->side, TRUE);
  2577.         }
  2578.     }
  2579.     /* If of a type that might be spotted if it does anything, check
  2580.        each side to see if they notice.  Note that the type is from
  2581.        *before* the action, not after (some actions may cause type changes). */
  2582.     if (u_spot_action(u)
  2583.         && !g_see_all()
  2584.         && !u_see_always(u)
  2585.         && in_area(unit->x, unit->y)) {
  2586.         for_all_sides(side2) {
  2587.         if (cover(side2, unit->x, unit->y) > 0) {
  2588.             /* (should call some sort of "glimpsing" routine) */
  2589.         }
  2590.         }
  2591.     }
  2592.     /* Check any scorekeepers that run after each action. */
  2593.     if (any_post_action_scores) {
  2594.         check_post_action_scores(unit, action, rslt);
  2595.     }
  2596.     } else {
  2597.     if (unit->plan) {
  2598.         unit->plan->lastaction = *action;
  2599.         unit->plan->lastresult = rslt;
  2600.     }
  2601.     if (unit->side && side_has_ai(unit->side)) {
  2602.         ai_react_to_action_result(unit->side, unit, rslt);
  2603.     }
  2604.     Dprintf("%s action %s can't be done, result is %s\n",
  2605.         unit_desig(unit), action_desig(action), hevtdefns[rslt].name);
  2606.     }
  2607.     /* Return success/failure so caller can use. */
  2608.     return rslt;
  2609. }
  2610.  
  2611. static void
  2612. play_action_messages(unit, action)
  2613. Unit *unit;
  2614. Action *action;
  2615. {
  2616.     int found = FALSE;
  2617.     char *soundname;
  2618.     Obj *rest, *head, *parms;
  2619.  
  2620.     for (rest = g_action_messages(); rest != lispnil; rest = cdr(rest)) {
  2621.     head = car(rest);
  2622.     if (consp(head)
  2623.         && symbolp(car(head))
  2624.         && strcmp(c_string(car(head)), actiondefns[(int) action->type].name) == 0) {
  2625.         found = TRUE;
  2626.         break;
  2627.     }
  2628.     if (consp(head)
  2629.         && consp(car(head))
  2630.         && symbolp(car(car(head)))
  2631.         && strcmp(c_string(car(car(head))), actiondefns[(int) action->type].name) == 0) {
  2632.         parms = cdr(car(head));
  2633.         if (parms == lispnil) {
  2634.         found = TRUE;
  2635.         break;
  2636.         }
  2637.         if (!((symbolp(car(parms))
  2638.            && strcmp(c_string(car(parms)), u_type_name(unit->type)) == 0)
  2639.           || match_keyword(car(parms), K_USTAR)
  2640.           || (symbolp(car(parms))
  2641.               && boundp(car(parms))
  2642.               && ((symbolp(symbol_value(car(parms)))
  2643.                   && strcmp(c_string(symbol_value(car(parms))), u_type_name(unit->type)) == 0)
  2644.                   || (numberp(symbol_value(car(parms)))
  2645.                       && c_number(symbol_value(car(parms))) == unit->type)))
  2646.           )) {
  2647.         continue;
  2648.         }
  2649.         if (parms == lispnil) {
  2650.         found = TRUE;
  2651.         break;
  2652.         }
  2653.         /* (should be able to match on particular action parameters also) */
  2654.     }
  2655.     }
  2656.     if (found) {
  2657.     if (stringp(cadr(head))) {
  2658.         notify(unit->side, "%s", c_string(cadr(head)));
  2659.     } else if (consp(cadr(head))
  2660.                        && symbolp(car(cadr(head)))
  2661.                        && strcmp(c_string(car(cadr(head))), "sound") == 0
  2662.                        && stringp(cadr(cadr(head)))) {
  2663.             soundname = c_string(cadr(cadr(head)));
  2664.             schedule_movie(unit->side, movie_extra_0, soundname);
  2665.             play_movies(add_side_to_set(unit->side, NOSIDES));
  2666.             return;
  2667.     } else {
  2668.     }
  2669.     }
  2670. }
  2671.  
  2672. /* Basic check that unit has sufficient acp to do an action. */
  2673.  
  2674. int
  2675. can_have_enough_acp(unit, acp)
  2676. Unit *unit;
  2677. int acp;
  2678. {
  2679.     int u = unit->type, maxacp, minacp;
  2680.  
  2681.     maxacp = u_acp(u);
  2682.     if (u_acp_turn_max(u) >= 0)
  2683.       maxacp = min(maxacp, u_acp_turn_max(u));
  2684.     maxacp = (u_acp_max(u) < 0 ? maxacp : u_acp_max(u));
  2685.     minacp = u_acp_min(u);
  2686.     return (maxacp - acp >= minacp);
  2687. }
  2688.  
  2689. int
  2690. has_enough_acp(unit, acp)
  2691. Unit *unit;
  2692. int acp;
  2693. {
  2694.     return ((unit->act->acp - acp) >= u_acp_min(unit->type));
  2695. }
  2696.  
  2697. /* This is true iff the unit has enough of each sort of supply to act. */
  2698.  
  2699. int
  2700. has_supply_to_act(unit)
  2701. Unit *unit;
  2702. {
  2703.     int m;
  2704.  
  2705.     for_all_material_types(m) {
  2706.     if (unit->supply[m] < um_to_act(unit->type, m))
  2707.       return FALSE;
  2708.     }
  2709.     return TRUE;
  2710. }
  2711.  
  2712. /* Make the consumed acp disappear, but not go below the minimum possible. */
  2713.  
  2714. void
  2715. use_up_acp(unit, acp)
  2716. Unit *unit;
  2717. int acp;
  2718. {
  2719.     int oldacp, newacp, acpmin;
  2720.  
  2721.     /* This can sometimes be called on dead or non-acting units,
  2722.        so check first. */
  2723.     if (alive(unit) && unit->act && acp > 0) {
  2724.         oldacp = unit->act->acp;
  2725.     newacp = oldacp - acp;
  2726.     acpmin = u_acp_min(unit->type);
  2727.     unit->act->acp = max(newacp, acpmin);
  2728.     /* Maybe modify the unit's display. */
  2729.     if (oldacp != unit->act->acp) {
  2730.         update_unit_display(unit->side, unit, TRUE);
  2731.     }
  2732.     }
  2733. }
  2734.  
  2735. /* Functions returning general abilities of a unit. */
  2736.  
  2737. int
  2738. can_research(unit)
  2739. Unit *unit;
  2740. {
  2741.     return type_can_research(unit->type);
  2742. }
  2743.  
  2744. int
  2745. type_can_research(u)
  2746. int u;
  2747. {
  2748.     int u2;
  2749.     
  2750.     for_all_unit_types(u2) {
  2751.     if (uu_acp_to_research(u, u2) > 0)
  2752.       return TRUE;
  2753.     }
  2754.     return FALSE;
  2755. }
  2756.  
  2757. int
  2758. can_toolup(unit)
  2759. Unit *unit;
  2760. {
  2761.     return type_can_toolup(unit->type);
  2762. }
  2763.  
  2764. int
  2765. type_can_toolup(u)
  2766. int u;
  2767. {
  2768.     int u2;
  2769.     
  2770.     for_all_unit_types(u2) {
  2771.     if (uu_acp_to_toolup(u, u2) > 0)
  2772.       return TRUE;
  2773.     }
  2774.     return FALSE;
  2775. }
  2776.  
  2777. int
  2778. can_create(unit)
  2779. Unit *unit;
  2780. {
  2781.     return type_can_create(unit->type);
  2782. }
  2783.  
  2784. int
  2785. type_can_create(u)
  2786. int u;
  2787. {
  2788.     int u2;
  2789.     
  2790.     for_all_unit_types(u2) {
  2791.     if (uu_acp_to_create(u, u2) > 0)
  2792.       return TRUE;
  2793.     }
  2794.     return FALSE;
  2795. }
  2796.  
  2797. int
  2798. can_complete(unit)
  2799. Unit *unit;
  2800. {
  2801.     return type_can_complete(unit->type);
  2802. }
  2803.  
  2804. int
  2805. type_can_complete(u)
  2806. int u;
  2807. {
  2808.     int u2;
  2809.     
  2810.     for_all_unit_types(u2) {
  2811.     if (uu_acp_to_build(u, u2) > 0)
  2812.       return TRUE;
  2813.     }
  2814.     return FALSE;
  2815. }
  2816.  
  2817. /* This tests whether the given unit is capable of doing repair. */
  2818.  
  2819. int
  2820. can_repair(unit)
  2821. Unit *unit;
  2822. {
  2823.     return type_can_repair(unit->type);
  2824. }
  2825.  
  2826. int
  2827. type_can_repair(u)
  2828. int u;
  2829. {
  2830.     int u2;
  2831.     
  2832.     for_all_unit_types(u2) {
  2833.     if (uu_acp_to_repair(u, u2) > 0)
  2834.       return TRUE;
  2835.     }
  2836.     return FALSE;
  2837. }
  2838.  
  2839. /* This tests whether the given unit is capable of doing repair. */
  2840.  
  2841. int
  2842. can_change_type(unit)
  2843. Unit *unit;
  2844. {
  2845.     return type_can_change_type(unit->type);
  2846. }
  2847.  
  2848. int
  2849. type_can_change_type(u)
  2850. int u;
  2851. {
  2852.     int u2;
  2853.     
  2854.     for_all_unit_types(u2) {
  2855.     if (uu_acp_to_change_type(u, u2) > 0)
  2856.       return TRUE;
  2857.     }
  2858.     return FALSE;
  2859. }
  2860.  
  2861. int
  2862. can_disband_at_all(side, unit)
  2863. Side *side;
  2864. Unit *unit;
  2865. {
  2866.     return (side != NULL
  2867.             && alive(unit)
  2868.         && side_controls_unit(side, unit)
  2869.         && (u_acp_to_disband(unit->type) > 0
  2870.             || !completed(unit)
  2871.             || side->designer));
  2872.             
  2873. }
  2874.  
  2875. /* The following is generic code. */
  2876.  
  2877. int
  2878. any_construction_possible()
  2879. {
  2880.     int u, u2;
  2881.     static int any_construction = -1;
  2882.  
  2883.     if (any_construction < 0) {
  2884.         any_construction = FALSE;
  2885.         for_all_unit_types(u) {
  2886.             for_all_unit_types(u2) {
  2887.                 if (uu_acp_to_create(u, u2) > 0) {
  2888.                     any_construction = TRUE;
  2889.                     return any_construction;
  2890.                 }
  2891.             }
  2892.         }
  2893.     }
  2894.     return any_construction;
  2895. }
  2896.  
  2897. /* Compose a legible description of a given action. */
  2898.  
  2899. char *
  2900. action_desig(act)
  2901. Action *act;
  2902. {
  2903.     int i, slen;
  2904.     char ch, *str;
  2905.  
  2906.     if (act == NULL)
  2907.       return "?null action?";
  2908.     if (act->type == A_NONE)
  2909.       return "[]";
  2910.     if (actiondesigbuf == NULL)
  2911.       actiondesigbuf = xmalloc(BUFSIZE);
  2912.     str = actiondesigbuf;
  2913.     sprintf(str, "[%s", actiondefns[act->type].name);
  2914.     slen = strlen(actiondefns[act->type].argtypes);
  2915.     for (i = 0; i < slen; ++i) {
  2916.     ch = (actiondefns[act->type].argtypes)[i];
  2917.     switch (ch) {
  2918.       case 'U':
  2919.         tprintf(str, " \"%s\"",
  2920.             unit_desig(find_unit(act->args[i])));
  2921.         break;
  2922.       default:
  2923.         tprintf(str, " %d", act->args[i]);
  2924.     }
  2925.     }
  2926.     if (act->actee != 0) {
  2927.     tprintf(str, " (#%d)", act->actee);
  2928.     }
  2929.     strcat(str, "]");
  2930.     return actiondesigbuf;
  2931. }
  2932.